2014-03-26 67 views
0

我在學校運行Ubuntu 13.10的計算機上有16 GB RAM。我寫了一個簡單的C程序來獲得總RAM,但它顯示的是非精確的結果,而不是16個,它打印出15個。如何使它精確,即使是更小的RAM大小?在家裏,我有768 MB RAM的計算機和我的程序顯示有錯誤的結果太:(在C,linux中獲取RAM大小,非精確結果

#include <sys/sysctl.h> 
#include <sys/types.h> 
#include <stdlib.h> 
#include <stdio.h> 

void getMemoryInfo() 
{ 
    FILE *meminfo = fopen("/proc/meminfo", "r"); 
    int totalMemory = 0; 
    if(meminfo == NULL) 
    { 
     exit(-1); 
    } 
    char buff[256]; 
    while(fgets(buff, sizeof(buff), meminfo)) 
    { 
     int ramKB; 
     if(sscanf(buff, "MemTotal: %d kB", &ramKB) == 1) 
     { 
      totalMemory = ramKB/1024.0; 
      totalMemory = totalMemory/1024.0; 
     } 
    } 
    if(fclose(meminfo) != 0) 
    { 
     exit(-1); 
    } 
    printf("%d\n", totalMemory); 
} 

int main() 
{ 
    getMemoryInfo(); 

    return 0; 
} 

回答

3

你是什麼看到是由浮點不準確引起的當你在浮點和整數之間以及打印浮點時必須小心

由於浮點數不能精確地表示所有數字,它經常嘗試儘可能接近。可能發生的是,而不是o女性16,totalMemory是像15.999999999987,然後當這個被轉換爲int,它被截斷至15

有可以解決這個問題有兩種方式:如果你知道totalMemory是整除1024*1024,那麼就使用整數(這在非整數千兆字節的情況下不起作用)。既然你使用的是整數,你也可以使用這種方法。 (768MB不能表示爲GB的整數)。

另一種選擇是添加一個epsilon來防止這種情況。換句話說,而不是使用totalMemory,你會使用類似totalMemory + 1e-7。這個epsilon太微不足道了,沒有什麼意義,但它可以將15.999...這樣的東西推到16


順便說一句,浮點問題只是你問題的一部分。如果你打算使用一個整數,你可能想使用MB而不是GB。一個整數如何表示4.5GB的內容(儘管這些日子非常少見)?

+0

FP這裏絕對不是一個準確的問題,雙打有52位數的尾數,我們正在處理整數,所以我們可以在沒有任何精度損失的情況下上升到2^53-1。 –

2

我曾經用這個代碼。適用於大多數操作系統

#if defined(_WIN32) 
#include <Windows.h> 

#elif defined(__unix__) || defined(__unix) || defined(unix) || (defined(__APPLE__) && defined(__MACH__)) 
#include <unistd.h> 
#include <sys/types.h> 
#include <sys/param.h> 
#if defined(BSD) 
#include <sys/sysctl.h> 
#endif 

#else 
#error "Unable to define getMemorySize() for an unknown OS." 
#endif 

/** 
* Returns the size of physical memory (RAM) in bytes. 
*/ 
size_t getMemorySize() 
{ 
#if defined(_WIN32) && (defined(__CYGWIN__) || defined(__CYGWIN32__)) 
    /* Cygwin under Windows. ------------------------------------ */ 
    /* New 64-bit MEMORYSTATUSEX isn't available. Use old 32.bit */ 
    MEMORYSTATUS status; 
    status.dwLength = sizeof(status); 
    GlobalMemoryStatus(&status); 
    return (size_t)status.dwTotalPhys; 

#elif defined(_WIN32) 
    /* Windows. ------------------------------------------------- */ 
    /* Use new 64-bit MEMORYSTATUSEX, not old 32-bit MEMORYSTATUS */ 
    MEMORYSTATUSEX status; 
    status.dwLength = sizeof(status); 
    GlobalMemoryStatusEx(&status); 
    return (size_t)status.ullTotalPhys; 

#elif defined(__unix__) || defined(__unix) || defined(unix) || (defined(__APPLE__) && defined(__MACH__)) 
    /* UNIX variants. ------------------------------------------- */ 
    /* Prefer sysctl() over sysconf() except sysctl() HW_REALMEM and HW_PHYSMEM */ 

#if defined(CTL_HW) && (defined(HW_MEMSIZE) || defined(HW_PHYSMEM64)) 
    int mib[2]; 
    mib[0] = CTL_HW; 
#if defined(HW_MEMSIZE) 
    mib[1] = HW_MEMSIZE;   /* OSX. --------------------- */ 
#elif defined(HW_PHYSMEM64) 
    mib[1] = HW_PHYSMEM64;   /* NetBSD, OpenBSD. --------- */ 
#endif 
    int64_t size = 0;    /* 64-bit */ 
    size_t len = sizeof(size); 
    if (sysctl(mib, 2, &size, &len, NULL, 0) == 0) 
     return (size_t)size; 
    return 0L;   /* Failed? */ 

#elif defined(_SC_AIX_REALMEM) 
    /* AIX. ----------------------------------------------------- */ 
    return (size_t)sysconf(_SC_AIX_REALMEM) * (size_t)1024L; 

#elif defined(_SC_PHYS_PAGES) && defined(_SC_PAGESIZE) 
    /* FreeBSD, Linux, OpenBSD, and Solaris. -------------------- */ 
    return (size_t)sysconf(_SC_PHYS_PAGES) * 
     (size_t)sysconf(_SC_PAGESIZE); 

#elif defined(_SC_PHYS_PAGES) && defined(_SC_PAGE_SIZE) 
    /* Legacy. -------------------------------------------------- */ 
    return (size_t)sysconf(_SC_PHYS_PAGES) * 
     (size_t)sysconf(_SC_PAGE_SIZE); 

#elif defined(CTL_HW) && (defined(HW_PHYSMEM) || defined(HW_REALMEM)) 
    /* DragonFly BSD, FreeBSD, NetBSD, OpenBSD, and OSX. -------- */ 
    int mib[2]; 
    mib[0] = CTL_HW; 
#if defined(HW_REALMEM) 
    mib[1] = HW_REALMEM;  /* FreeBSD. ----------------- */ 
#elif defined(HW_PYSMEM) 
    mib[1] = HW_PHYSMEM;  /* Others. ------------------ */ 
#endif 
    unsigned int size = 0;  /* 32-bit */ 
    size_t len = sizeof(size); 
    if (sysctl(mib, 2, &size, &len, NULL, 0) == 0) 
     return (size_t)size; 
    return 0L;   /* Failed? */ 
#endif /* sysctl and sysconf variants */ 

#else 
    return 0L;   /* Unknown OS. */ 
#endif 
}