C++ c++;,浮动到整型铸造
我只想澄清以下这些情况:C++ c++;,浮动到整型铸造,c++,types,casting,C++,Types,Casting,我只想澄清以下这些情况: #define MAP_CELL_SIZE_MIN 0.1f float mMapHeight = 256; float mScrHeight = 320; int mNumRowMax; 案例1: mNumRowMax = mMapHeight/( MAP_CELL_SIZE_MIN * mScrHeight ); mNumRowMax现在是7,但实际上它必须是8(256/32),如果我将MAP\u CELL\u SIZE\u MIN的定义更改为仅0.1,那么
#define MAP_CELL_SIZE_MIN 0.1f
float mMapHeight = 256;
float mScrHeight = 320;
int mNumRowMax;
案例1:
mNumRowMax = mMapHeight/( MAP_CELL_SIZE_MIN * mScrHeight );
mNumRowMax
现在是7,但实际上它必须是8(256/32),如果我将MAP\u CELL\u SIZE\u MIN
的定义更改为仅0.1
,那么它就变为真,mNumRowMax
是8,那么'f'
案例2:
float tmp = mMapHeight/( MAP_CELL_SIZE_MIN * mScrHeight );//tmp = 8.0
mNumRowMax = tmp;
mNumRowMax
现在是8,所以有人能帮我理解第一种情况下的错误吗mNumRowMax
是7当一个浮点数被转换为整数时,该值被截断而不是四舍五入,即所有的小数都被“截断”。看起来您遇到了四舍五入错误
一个简单的修复方法可能是使用double而不是float
如果这不是一个选项,那么您可能需要舍入到整数。例如,如果您有一个浮点值f,则执行与intx=(int)(f+0.5)等效的操作代码>发生的是
5[expr]
10浮点操作数的值和浮点表达式的结果的值可以比类型要求的精度和范围更高;类型不会因此而改变。55)
55)强制转换和赋值运算符仍必须按照5.4、5.2.9和5.17中所述执行其特定转换
(C++03;C99中的6.3.1.8(2)与C11的n1570草案几乎相同;我相信C++11中的要点是相同的。)
在下面,我假设一个类似IEEE-754的二进制浮点表示
用分数十六进制表示法
1/10 = 1/2 * 3/15
= 1/2 * 0.33333333333...
= 2^(-4) * 1.999999999...
因此,当这四舍五入到b
位的精度时,您得到
2^(-4) * 1.99...9a // if b ≡ 0 (mod 4) or b ≡ 1 (mod 4)
2^(-4) * 1.99...98 // if b ≡ 2 (mod 4) or b ≡ 3 (mod 4)
其中,小数部分的最后一个十六进制数字分别在3、4、1、2最高有效位之后截断
现在320=2^6*(2^2+1)
,因此r*320
的结果r
是0.1
四舍五入到b
位,是完全精确的(忽略2的幂)
用b+3
位表示b≡ 0(模块4)
或b≡ 1(4型)
和
6.66...60
+ 1.99...98
-----------
7.ff...f8
用b+2
位表示b≡ 2(模块4)
或b≡ 3(mod 4)
在每种情况下,将结果四舍五入到b
位的精度正好得到32,然后得到256/32=8
,作为最终结果。但如果使用精度更高的中间结果,则
256/(0.1 * 320)
略小于或大于8
对于具有24(23+1)位精度的典型32位浮点
,如果中间结果以至少53位的精度表示:
0.1f = 1.99999ap-4
0.1f * 320 = 32*(1 + 2^(-26))
256/(0.1f * 320) = 8/(1 + 2^(-26)) = 8 * (1 - 2^(-26) + 2^(-52) - ...)
在案例1中,结果直接从中间结果转换为intint
。由于中间结果略小于8,因此它被截断为7
在情况2中,中间结果在转换为int
之前存储在float
中,因此首先将其四舍五入到24位精度,结果正好是8位
现在,如果您去掉f
后缀,0.1
是一个double
(大概有53位精度),两个浮点
将升级为double
,用于计算,并且
0.1 = 1.999999999999ap-4
0.1 * 320 = 32*(1 + 2^(-55))
256/(0.1 * 320) = 8 * (1 - 2^(-55) + 2^(-110) - ...)
如果以double
精度执行计算1+2^(-55)==1
并且已经0.1*320==32
如果以64位或更高精度(考虑x87)的扩展精度执行计算,则文字0.1
很可能根本不会转换为double
精度,并直接与扩展精度一起使用,这再次导致乘法0.1*320
的结果正好是32
如果在double
精度下使用文字0.1
,但在更高精度下执行计算,如果中间结果从更高精度的表示中直接截断为int
,则再次生成7,如果在转换为int
之前删除多余的精度,则生成8
(旁白:gcc/g++4.5.1在所有情况下都会产生8,无论优化级别如何,在我的64位机器上,我还没有在32位机器上尝试过。)
我不完全确定,但我认为这违反了标准,它应该首先去除多余的精度。有语言律师吗?我知道该值在施法时被截断而不是四舍五入,但这个浮点值是8.0,所以截断后它仍然必须是8,而不是7@nvhausid由于浮点数的格式,计算机不能准确地表示某些数字。浮点值可能是代码> 7 99999 或打印时类似的但舍入的。<代码>数学。循环()/代码>将为您处理这个问题。@ JohnGaughan不是C或C++,只是在JavaScript中。我在想java,完全错过了C++。在标题中。似乎您可以重构此代码以使用整数并完全避免浮点。您的数学可能会有所不同(例如,除以10而不是乘以0.1),但保证精确。考虑到你的最终结果是一个整数,你有理由使用浮点吗?这篇文章只是为了说明我遇到的问题,我的实际代码是不同的,我需要使用这种形式。我现在使用0.1而不是0.1f,只是想了解可能重复的问题。我很困惑如果我从
float
转换到int
会发生什么。因为float和int的“编码”不同,所以转换位不会直接导致值不同。像C这样的语言如何处理浮点类型转换?编辑:网站上的人建议我使用static\u cast(floatVar)
。这是否执行了安全强制转换所需的步骤?通常,有一条机器指令用于转换,编译器只会使用它。如果没有这样的机器指令,实现(如果有这样一个不方便的平台)将
0.1 = 1.999999999999ap-4
0.1 * 320 = 32*(1 + 2^(-55))
256/(0.1 * 320) = 8 * (1 - 2^(-55) + 2^(-110) - ...)