浮点数显示问题
问题描述:在本地系统中定义了一个float变量,并赋一个很大值,但程序运行结果与原始值不一致。如下测试程序:
int main(int argc, char* argv[]) { float fvalue = 123456789012.0; float *p = &fvalue; printf("%f\n", fvalue); TRACE("\r\n val=%f", fvalue);
return 0; } |
程序运行后输出结果为:123456790528.0
分析了浮点数在内存中的表示方式后发现是float的精度问题。
32位浮点数的二进制表示方式为:R = S * M*2E-127
E为实际的指数加上固定值127。
符号位—1bit |
阶码E—8bit |
尾数M—23bit |
1 |
1111 1111 |
111 1111 1111 1111 1111 1111 |
数值123456789012转换为二进制为:1110010111110100110010001101000010100 共37位,那么小数点左移36位后为
1. 110010111110100110010001101000010100,由于32位浮点数尾数为23位,那么只能保留小数点后前23位,即:1.11001011111010011001000,后面12位数根据大小进行四舍五入,比如这里的1101000010100转换后为6676大于213-1,那么向前进1,最终存储表示为:1.11001011111010011001001,阶码为36+127=163。
也就是经过转换后精度有丢失,转换后的数据为:1.110010111110100110010010000000000000,去掉小数点后,即为计算机存储的数据大小,值为123456790528。
结论:如果使用float定义,当数据大于16777215(24个二进制的1,111111111111111111111111)后,就会出现精度问题,与原始数据的差距范围取决于该数据的二进制表示中总位数与24的差值,比如这里是37,那么范围为0-237-24