Search code examples
matlabbinaryprecisionfwritefread

fread and fwrite in matlab not exact


I would like to save float numbers in a binary file and read them afterwards for further processing. Unfortunately, fwrite and afterwards fread does change the number.

Following simple example:

% Number to store
A = 0.123456789101112

% Generate and open txt file
fid = fopen('test_fread.txt','w','b');

% write A into test_fread.txt
fwrite(fid,A,'float32');

% close file
fclose(fid)

% open txt file
fid = fopen('test_fread.txt','r','b');

% read the file
fread(fid,'float32')

ans = 0.123456791043282

The answer is different than the input. How can I fix this? What should I search for? Is it rounding, precision or another problem?


Solution

  • Floating point numbers are never exact. single precision floats (float32) only have 6-9 decimals of precision. For the pure decimal case this translates to the issue that you're seeing. The effect is more exaggerated if you also have an integer component:

    % Sample number
    A = 123456789.123456789;
    
    % Write, rewind, and read back in
    fID = fopen('test_fread.txt', 'w+', 'b');
    fwrite(fID, A, 'float32');
    frewind(fID);
    B = fread(fID,'float32');
    fclose(fID);
    
    fprintf('A: %15.15f\nB: %15.15f\n', A, B);
    

    Which returns:

    A: 123456789.123456790000000
    B: 123456792.000000000000000
    

    Note that MATLAB casts B as a double here.

    MATLAB's default data type, double (float64) has double the bits available, which will give you 15-17 significant decimal digits. Using the previous example we can try:

    % Sample number
    A = 123456789.123456789;
    
    % Write, rewind, and read back in
    fID = fopen('test_fread.txt', 'w+', 'b');
    fwrite(fID, A, 'float64');
    frewind(fID);
    B = fread(fID,'float64');
    fclose(fID);
    
    fprintf('A: %15.15f\nB: %15.15f\n', A, B);
    

    Which returns:

    A: 123456789.123456790000000
    B: 123456789.123456790000000
    

    Yay.

    If you need better precision in MATLAB than double you will need to look into using vpa, which is part of the Symbolic Math Toolbox, or a similar package that offers higher/variable precision.