目标C - 通过浮点除以长而不会丢失精度

时间:2017-07-31 15:10:05

标签: objective-c floating-point precision long-integer divide

将long类型与float分开时,我遇到了精度问题,最终弄乱了应用程序中的计算。假设我只是将毫秒转换为秒,因为这是我们最终的要求。以下是一个示例测试用例

long startTimeMS = 2529095;
NSTimeInterval expectedStartTime = 2529.095
NSTimeInterval startTime = startTimeMS / 1000.f; //Results to "2529.09497"
double startTimeDouble = startTimeMS / 1000.0 // Results to "2529.0949999999998"

XTCAssert(startTime == expectedStartTime, @"Invalid start time")

通过浮动划分长度,它会失去精确度的千分之三。类似于长除以双。

如何将其划分为与预期的开始时间相同?我猜测四舍五入到最接近千分之一也是好的但我在这里找到的舍入方法也不可靠这样

float roundToTwo(float num)
{
    return round(100 * num) / 100;
}

最有可能返回相同的值

2 个答案:

答案 0 :(得分:1)

你误解了浮点的工作原理。浮点类型floatdouble二进制类型。

您的小数部分0.095等于9/100 + 5/1000 - 所有小数部分都是1/(10^n)分数的总和。

现在考虑普通分数,等于1/3的小数分数是多少?它是3/10 + 3/100 + 3/1000 + ...或等效0.333...没有确切的方式将其表示为小数分数相同。

对于floatdouble类型,小数部分是1/(2^n)分数的总和。与上述类似,并非所有小数部分都可以精确地写为二进制分数。

除了使用不同的基数(十进制与二进制)引起的差异之外,计算机浮点数限制在任何数字的位数,而实际数学是无限制的,因此计算可能不会产生 exact < / em>结果。

由于上述原因,从不测试精确相等,而是两个数字的差值是否小于一个小值(可能根据数字的大小而变化),这是一个很好的浮点练习。在你的情况下,你可能会认为两个数字相等&#34;如果它们的差异小于0.1毫秒。

现在已经说过你给出的特定例子中的所有内容,如果纠正的话,数字实际上是相同的,但2529.095都不是:

long startTimeMS = 2529095;
NSTimeInterval expectedStartTime = 2529.095;     // Result is approx "2529.0949999999998"
NSTimeInterval startTime = startTimeMS / 1000.0; // Result is approx "2529.0949999999998"

这两个数字将相等,但并非所有值都是如此。将断言写为:

会更好
XTCAssert(fabs(startTime - expectedStartTime) <= 0.0001, @"Invalid start time");

其中0.0001应该是足够小的一小部分你认为这两个值&#34;等于&#34;。

如果要进行需要精确的工作,你真的应该阅读浮点运算,因为你做了更多的操作,由于基数和有限数字的累积而产生差异,并且有一些技术可以最小化和处理这些差异。

HTH

答案 1 :(得分:0)

你不应该为这个操作使用一个浮点数 - 因为浮点数中十进制数的基数10表示总是产生不均匀的数字。更好的解决方案是使用定点算术并将所有内容乘以1000(如果需要更多小数精度,则将其乘以更多)。这避免了浮点计算中固有的舍入误差。

请参阅:

https://softwareengineering.stackexchange.com/questions/101163/what-causes-floating-point-rounding-errors

有关导致这些错误的更好答案。