Результат инициализации C float является неожиданным - PullRequest
0 голосов
/ 19 апреля 2019

Сообщество Visual Studio 2019 переменная типа float - это не то, к чему я ее инициализирую. Я сделал это менее точным в надежде избежать усечения. Разве это не «управляемо»?

пытался заставить init округлять другим способом

int main()
{
    // where did my 6 go?
    float b = 80.123456F;
    printf("b:[%f]\n", b);

    // rounds up
    float c = 80.1234569F;
    printf("c:[%f]\n", c);

    // rounds up
    float d = 80.1234561F;
    printf("d:[%f]\n", d);


    // appends a 1
    float e = 80.12345F;
    printf("e:[%f]\n", e);

    // prints what's initialized
    float f = 80.123451F;
    printf("f:[%f]\n", f);

    // prints what's initialized
    float g = 80.123459F;
    printf("g:[%f]\n", g);
}
b:[80.123459]
c:[80.123459]
d:[80.123459]
e:[80.123451]
f:[80.123451]
g:[80.123459]

Я начал с отладчика и написал это, чтобы соответствовать требованиям SO. В моем случае отладчик соответствовал отпечаткам

Ответы [ 3 ]

0 голосов
/ 19 апреля 2019

Два выпуска:

  • printf со спецификатором преобразования %f выполняет свое округление значений с плавающей запятой для отображения. Вы можете контролировать количество отображаемых после десятичной точки цифр с помощью спецификатора точности: printf( "%.8f\n", b ); будет печатать до 8 цифр после десятичной точки, а printf( "%.16f\n", a); будет печатать 16. Однако не доверяйте отображаемому значению, потому что ...

  • Бесконечное число действительных значений не может вписаться в конечное число битов, поэтому большинство реальных значений не могут быть представлены точно - вы получите приближение, которое хорошо только для такого количества десятичных цифр. Типы float с одинарной точностью не гарантируют намного больше точности от 6 до 7 десятичных цифр (это не просто количество цифр после десятичной точки, это общее количество цифр ). double дает вам что-то вроде от 10 до 11 цифр. Если вам нужно представлять значения с многими цифрами точности (более 12 или около того), то вам нужно пройти мимо собственных типов с плавающей запятой и использовать стороннюю библиотеку с множественной точностью.

0 голосов
/ 20 апреля 2019

Решением этой проблемы может быть изменение типов данных.Даже если double работает так же, как и float, аппроксимируя большой диапазон действительных чисел конечным набором рациональных чисел, двойники настолько близки друг к другу, что ошибка округления будет иметь меньшее значение.

Например, значения float, наиболее близкие к действительному числу 80.123456, составляют 80.12345123291015625 и 80.1234588623046875.В double значениях близких к 80.123456 являются 80,123456000000004451067070476710796356201171875 и 80,1234559999999902402123552747070789337158203125.

1008 *float действительно имеет свои преимущества, в ситуациях, в которых вы имеете дело с очень большими наборами очень низких цифр точности, но double являетсяболее общий полезный тип.При вводе физической величины в программу с использованием double ошибка измерения будет превышать ошибку округления.
0 голосов
/ 19 апреля 2019

Поплавки имеют точность не более 7 значащих цифр. Не 7 десятичные цифры. 80.123456F имеет 8 значащих цифр, так что это не сработает.

В то время как 80.12345 имеет только 7 значащих цифр, на самом деле он заканчивается на отметке 80.1234512329101562. Который, пока вы не пытаетесь напечатать больше цифр, чем он, это нормально. К сожалению,% f всегда печатает 6 цифр после десятичной точки. Что в данном случае является еще одним, чем имеет смысл. Вы бы немного лучше с% g, где вместо этого вы можете указать количество значащих цифр.

...