准确地提取浮点的小数部分

时间:2013-06-06 15:05:02

标签: c++ arduino decimal floating-accuracy

注意:我在C ++的Arduino变体中编写以下代码。

从给定的浮点数(总是带有四位小数),我希望只将小数部分(“尾数”)提取为整数。

所以我尝试了这种方法:

void ExtractDecimalPart(float Value) {
  int IntegerPart = (int)(Value);
  int DecimalPart = 10000 * (Value - IntegerPart); //10000 b/c my float values always have exactly 4 decimal places
  Serial.println (DecimalPart);
}

但上述结果如下:

ExtractDecimalPart (1234.5677); //prints 5677
ExtractDecimalPart (1234.5678); //prints 5677
ExtractDecimalPart (1234.5679); //prints 5678
注意后两个打印错了;我猜这是由于浮点精度问题。

解决上述问题的经济方法是什么?

3 个答案:

答案 0 :(得分:2)

这是一个很酷的问题。

我将假设ardiuno正在使用IEEE 754 当你设置一个等于1234.5677的浮点数时,最接近4个字节的浮点数是1.2345677490234375E3,它看起来像十六进制的0x449A522B。

但是当您将1234.5678放入浮点数时,它可以形成的最佳数字是1.2345677490234375E3 这只是短暂的。在十六进制中,它是0x449A522B。

因此,在简短的浮动中,只能存储需要使用数字的数字的数字。

答案 1 :(得分:1)

避免浮点精度问题的最简单方法是将数字转换为字符串,然后仅打印点之后的数字。

修改

我不确定如何使用arduino的版本c++,所以请随时编辑我的答案以添加每个人的示例!

答案 2 :(得分:0)

32位float有23位尾数,因此它只能保存约7位精度。您的示例使用8位数字,因此最后一个只是“垃圾”。您必须使用更高精度的浮点类型(标准C ++中为doublelong double)。

在Arduino上取决于变体you may have a standard compliant 64-bit double type or not。如果doublefloat完全相同,则您有多种解决方案:

  • 编写或使用一些double数学库。
    • 或者如果double在8位MCU上的成本太高,那么您可以创建自定义浮点类型,如40位或48位。
    • 或者您可以使用float-float arithmetic类型like this
  • 使用fixed-point type。由于您总是有4个十进制数字,因此这个用例最适合您。
    • 您可以使用Q26.6或Q25.7二进制格式以获得更好的算术性能
    • 或者更好地使用缩放的十进制类型,最后4位数作为小数部分,以获得更好的十进制数学输出。在某些情况下,您还可以分别存储最后4位十进制数字和整数部分,但请注意此实现。

您可以在this question代码中找到有关定点的更多信息