使用C ++和往返数字进行舍入

时间:2014-01-02 12:56:01

标签: c++ ieee-754

我有一个类在内部用固定点表示一些数量为32位整数,有一些任意分母(它既不是2的幂,也不是10的幂)。

为了与其他应用程序通信,数量在输出时转换为普通旧的双倍,并在输入时返回。作为类中的代码,它看起来像:

int32_t quantity;
double GetValue() { return double(quantity) / DENOMINATOR; }
void SetValue(double x) { quantity = x * DENOMINATOR; }

现在我需要确保如果我将一些值输出为double并将其读回,我将始终获得相同的值。即该

x.SetValue(x.GetValue());

永远不会改变x.quantityx是包含上述代码的类的任意实例。)

双重表示具有更多的精度数字,因此它应该是可能的。但是上面的简单代码几乎肯定不会出现这种情况。

  • 我需要使用什么样的舍入和
  • 如何找到关键的角落情况来测试圆角是否确实正确?

2 个答案:

答案 0 :(得分:3)

当您转换为double时,任何32位都将被准确表示,但是当您除以然后乘以任意值时,您将获得类似的值但不完全相同。每次操作最多丢失一位,这意味着在重新转换为int之前,你的double将几乎相同。 但是,由于int强制转换是截断,当非常小的错误将2.000变为1.999时,您将得到错误的结果,因此您需要做的是在回退之前进行简单的舍入任务。

如果你有C ++ 11,你可以使用std::lround(),否则你可以编写自己的舍入函数。

你可能在这里不太关心公平,所以共同的int(doubleVal+0.5)将对积极作用。如果看起来很可能,你有负面影响,试试这个:

int round(double d) { return d<0?d-0.5:d+0.5; }

答案 1 :(得分:2)

您描述的问题与使用不同基数在二进制和十进制表示之间进行转换时存在的问题相同。至少它存在,如果你想让double表示与原始值的良好近似(否则你可以将你的32位值乘以你的固定分母并将结果存储在{{1 }})。

假设您希望double表示与您的实际值相近,则转换非常重要!从内部表示到double的转换可以使用 Dragon4 (“如何准确打印浮点数”,Steele&amp; White)或 Grisu ( “如何快速准确地打印浮点数”,Loitsch;我不确定这个算法是否独立于基数。反过来可以使用 Bellerophon (“如何准确读取浮点数”,Clinger)完成。这些算法并非完全无关紧要,但是......