1

注意:我在 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

注意后两者打印错误;我猜这是由于浮点精度问题。

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

4

3 回答 3

2

这是一个很酷的问题。

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

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

因此,简而言之,浮点数不能存储需要您使用的位数的数字。

于 2013-06-06T15:28:57.757 回答
1

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

编辑

我不确定如何使用 arduino 的版本来做到这一点,c++因此请随时编辑我的答案以添加示例!

于 2013-06-06T15:22:18.280 回答
0

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

在 Arduino 上,取决于变体,您可能有或没有符合标准的 64 位double类型。如果与您有几种解决方案double完全相同:float

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

您可以在此问题标签中找到有关定点的更多信息

于 2013-07-27T15:04:24.987 回答