Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/objective-c/23.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Objective c 正确减去浮点值_Objective C_Ios_C_Floating Point - Fatal编程技术网

Objective c 正确减去浮点值

Objective c 正确减去浮点值,objective-c,ios,c,floating-point,Objective C,Ios,C,Floating Point,我正在尝试创建一个值数组。这些值应为“2.4,1.6,8,0”。我每一步都在减法.8 我就是这样做的(代码片段): 我不想要一个介于.8和0之间的非常小的数字。有标准的方法来截断这些值吗?另一种方法是将通过减法得到的数字乘以10,然后转换为整数,然后将该整数除以10.0 使用如下地板功能(floorf),您可以轻松完成此操作: 浮动新值=地板(旧值*10)/10 您看到的是良好的旧式浮点舍入错误。幸运的是,在您的情况下,它应该很容易处理。只需夹紧: if( val < increment

我正在尝试创建一个值数组。这些值应为“2.4,1.6,8,0”。我每一步都在减法.8

我就是这样做的(代码片段):


我不想要一个介于.8和0之间的非常小的数字。有标准的方法来截断这些值吗?

另一种方法是将通过减法得到的数字乘以10,然后转换为整数,然后将该整数除以10.0

使用如下地板功能(floorf),您可以轻松完成此操作:


浮动新值=地板(旧值*10)/10

您看到的是良好的旧式浮点舍入错误。幸运的是,在您的情况下,它应该很容易处理。只需夹紧:

if( val < increment ){
    val = 0.0;
}

3.2和.8都不能精确地表示为32位浮点。最接近3.2的可表示数字为3.2000000476837158203125(十六进制浮点,0x1.9999ap+1)。最接近.8的可表示数字为0.800000011920928955078125(0x1.99999 AP-1)

当从3.2000000476837158203125中减去0.800000011920928955078125时,精确的数学结果为2.400000035762786865234375(0x1.333333 8p+1)。这个结果也不能精确地表示为32位浮点。您可以在十六进制浮点中轻松地看到这一点。32位浮点具有24位有效值。“1×333333”在“1”中有一位,中间六位的24位,8位中的另一位。因此,结果被舍入到最接近的32位浮点,即2.400万95367331640625(0xTrace33333 4p+1)。 从中减去0.800000011920928955078125,得到1.6000001430511474609375(0x1.99999 cp+0),这正是可表示的。(1是一位,“5个9”是20位,“c”有两个有效位。“c”中的低位两位是尾随零,可以忽略不计。因此有23个有效位。)

从中减去0.800000011920928955078125,得到0.800001113021850585959375(0x1.99999 EP-1),这也是可精确表示的

最后,从中减去0.800000011920928955078125得到1.1920928955078125e-07(0x1p-23)


这里要吸取的教训是,浮点并不代表所有数字,它会对结果进行四舍五入,以获得它所能代表的最接近的数字。在编写使用浮点运算的软件时,必须理解并考虑这些舍入操作。考虑到这一点的一种方法是使用您知道可以表示的数字。其他人建议使用整数算术。另一种选择是使用大多数可以用浮点表示的值,其中包括最多224个整数。你可以从32开始,减去8,得到24,16,8,0。这些将是用于循环控制和无错误继续计算的中间值。当您准备好交付结果时,您可以除以10,生成接近3.2、2.4、1.6、8和0的数字(精确)。这样,您的算法只会在每个结果中引入一个舍入误差,而不是一次又一次地累积舍入误差。

我的意思是截断平均值和SD,这样它们就不会给我很小的值。我编辑了我的答案,以展示使用floorf函数实现这一点的简单方法。我不明白为什么.8的浮点表示的尾数是1.10011001。。。(重复)而不是精确的1.100100000000。(.8用浮点表示时存储为1.6*2^-1。所选的1.6在较低的有效位中有一些古怪的地方,这导致了问题中出现的错误)我认为发生了一些奇怪的事情。我主要关心的是找到一个切实可行的解决办法,但我也对了解官方原因/解释感兴趣。可能我没有使用正确的数据类型(float)。不,我认为float应该可以。注意:10.0中的“.0”在执行除法时很重要。是的,这是类型提升:
一些int/10
会导致
int
,这不会产生小数。除以一个文本
float
“首先提升”int,这会给出一个
float
结果。以这种方式进行钳制是一个坏主意,因为有时舍入会导致迭代变量略小于增量,而不是略大于增量,这种钳制将有效地跳过迭代。例如,如果初始值为3.6f(而不是3.2f),而步长为.9f(而不是.8f),则每次迭代中的值将略低于3.6、2.7、1.8和.9。此时,钳制将略低于.9的值转换为零,并跳过一次迭代。@Eric:我曾考虑在比较
if(val<(increment-buffer))
中添加一个“epsilon”,但考虑到问题的简单性,我认为这是一次过多的操作。我认为整数解更可取。不过,对问题的解释很好。
minusRegion = (
    "2.4",
    "1.6",
    "0.8000001",
    "1.192093e-07",
    0
)
if( val < increment ){
    val = 0.0;
}
int increment = 8;
int val = 32;

while( val > 0 ){
    val -= increment;

    float new_float_val = val / 10.0;
};