简体   繁体   English

C中的舍入浮点

[英]Rounding floats in C

While testing the float type and printing it with it's format specifier %f I was testing it's rounding methods. 在测试浮点类型并使用格式说明符%f对其进行打印时,我正在测试其舍入方法。

I've declared the variable as float and gave it the value 5.123456. 我已将变量声明为float,并为其指定了值5.123456。 As you know float must represent at least 6 significant figures. 如您所知,浮点数必须至少代表6个有效数字。

I then changed it's value to 5.1234567 and printed the value with the %f . 然后,我将其值更改为5.1234567并用%f打印该值。 It baffles me why it prints out as 5.123456. 这让我感到困惑,为什么它输出为5.123456。 But if I change the variable value to 5.1234568, it prints out as 5.123457. 但是,如果我将变量值更改为5.1234568,它将输出为5.123457。 It rounds properly. 正确舍入。

If I haven't made myself clear or the explanation is very confusing: 如果我不清楚,或者解释很混乱:

float a = 5.1234567
printf("%d", a); 
// prints out as 5.123456

float a = 5.1234568
printf("%d", a); 
// prints out as 5.123457

I've compiled using CodeBlocks and MinGW, same result. 我已经使用CodeBlocks和MinGW进行了编译,结果相同。

OP is experiencing the effects of double rounding OP正在经历双舍入的影响

First, the values 5.123456, 5.1234567, etc. are rounded by the compiler to the closest representable float . 首先,编译器将值5.123456、5.11234567等舍入到最接近的可表示float Then printf() is rounding the float value to the closest 0.000001 decimal textual representation. 然后printf()float四舍五入到最接近的0.000001十进制文本表示形式。


I've declared the variable as float and gave it the value 5.123456. 我已将变量声明为float,并为其指定了值5.123456。 As you know float must represent at least 6 significant figures. 如您所知,浮点数必须至少代表6个有效数字。

A float can represent about 2^32 different values. float可以表示大约2 ^ 32个不同的值。 5.123456 is not one of them. 5.123456不是其中之一。 The closest value a typical float can represent is 5.12345600128173828125 and that is correct for 6 significant digits: 5.12345... 典型float可以代表的最接近值是5.12345600128173828125,它对于6个有效数字是正确的:5.12345 ...

float x = 5.123456f;
//  5.123455524444580078125 representable float just smaller than 5.123456
//  5.123456                OP's code
//  5.12345600128173828125  representable float just larger  than 5.123456 (best)

// The following prints 7 significant digits
// %f prints 6 places after the decimal point.
printf("%f", 5.123456f); // --> 5.123456

With 5.1234567, the closest float has an exact value of 5.123456478118896484375. 对于5.1234567,最接近的float的精确值为5.123456478118896484375。 When using "%f" , this is expected print rounded to the closest 0.000001 or 5.123456 当使用"%f" ,预期此打印将四舍五入到最接近的0.0000015.123456

float x = 5.1234567f;
//  5.123456478118896484375 representable float just smaller than 5.1234567 (best)
//  5.1234567                OP's code
//  5.1234569549560546875   representable float just larger  than 5.1234567

// %f prints 6 places after the decimal point.
printf("%f", 5.1234567f); // --> 5.123456

Significant digits is not the number of digit after the decimal point. 有效数字不是小数点后的位数。 It is the number of digits starting with the left-most (most significant) digit. 它是从最左(最高有效)位开始的位数。

To print a float to 6 significant figures, use "%.*e" . 要将float打印为6位有效数字,请使用"%.*e"
See Printf width specifier to maintain precision of floating-point value for more details. 有关更多详细信息,请参见Printf宽度说明符以保持浮点值的精度

float x = 5.1234567;         
printf("%.*e\n", 6 - 1, x);  // 5.12346e+00
                             // x xxxxx   6 significant digits

There is no exact float representation for the number 5.1234567 you intend to show here. 您要在此处显示的数字5.1234567没有确切的浮点表示形式。

If you check here: https://www.h-schmidt.net/FloatConverter/IEEE754.html 如果您在此处查看: https : //www.h-schmidt.net/FloatConverter/IEEE754.html

You can see that this number is converted into 5.1234565, or the double 5.1234564781188965 and this rounds down, 您会看到此数字已转换为5.1234565或双精度的5.1234564781188965,并将其四舍五入,

While the number 5.1234568 is representable in float, and has a double representation of 5.123456954956055, and this rounds up. 数字5.1234568用浮点数表示,并且具有5.123456954956055的双精度表示,因此将其取整。

There are two levels of rounding going on: 舍入分为两个级别:

  1. Your constant of 5.1234567 gets rounded to the nearest value which can be represented by a float (5.123456478...). 您的常数5.1234567会四舍五入为最接近的值,该值可以用浮点数(5.123456478 ...)表示。
  2. The float gets rounded to 6 digits when printed. 浮点数在打印时四舍五入到6位数字。

It will become obvious if you print the value with more digits. 如果您打印更多位数的值,这将变得显而易见。

What it comes down to is that the mantissa of a float has 23 bits and this is not the same as 6 decimal digits (or any number of digits really). 得出的结论是,浮点数的尾数有23位,这与6个十进制数字(或实际上是任意数字)不同。 Even some apparently simple values like 0.1 don't have an exact float representation. 甚至一些看似简单的值(例如0.1)也没有精确的浮点表示形式。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM