处理:仅将float的小数提取为float

时间:2013-12-01 00:35:07

标签: math floating-point processing

我需要知道浮点数的小数,这是一个像

一样浮点数的函数
float in1 = 2013.45
float in2 = 367.678

并导致

float out1 = 0.45
float out2 = 0.678

我见过内置的nf(),但它返回一个String。实现这一目标最优雅/最方便的方法是什么?

编辑:我试过了

float in = 2013.45;
float out = in-floor(in);

但结果是0.44995117而不是0.45。

3 个答案:

答案 0 :(得分:3)

  

编辑:我试过了

float in = 2013.45;
float out = in-floor(in);
     

但结果是0.44995117而不是0.45。

这可能是正确的。你在这里看到的是loss of precision

为简单起见,首先让我们假装计算机在基数10(换句话说,十进制数字系统)中工作。

A 32 bit float has 7 correct significant decimal digits. 2013.45在内部表示为2013.450。现在,当您减去整数部分时,4个有效数字变为零:

   2013.450
 - 2013
 ----------
       .450

换句话说, 4位有效数字丢失,结果最多只能精确到3位有效数字。您需要更多的输入 2013.450数字才能获得更精确的结果。不幸的是,您只能使用32位浮点数限制为7位数,并且您无能为力。

浮点计算接下来会发生的是(组成)零附加到结果,直到我们再次有7位有效数字。它被称为规范化。在基数10,我们意外幸运,因为正确的数字恰好是0(最有可能是你混淆的原因)但是计算机在基数2中工作。这段代码显示了实际计算是如何内部执行,十六进制格式和C:

#include <stdio.h>

int main(int argc, char** argv) {
  float       x = 2013.45;
  float floor_x = 2013;
  float       y = x - floor_x;

  printf("      x  = %a\n", x);
  printf("floor(x) = %.6a\n", floor_x);
  printf("      y  = %.6a\n", y);
}

打印:

       x  = 0x1.f75cccp+10 
 floor(x) = 0x1.f74000p+10
       y  = 0x1.ccc000p-2

正如您所看到的,y通过在后面添加三个0来重新规范化。但是,基数16中的正确数字应该是c我们在基数10中幸运只有完全意外,因为在基数10中附加的零和真实数字会重合。


还有一点需要注意。 打印功能可以组成垃圾数字。计算机在内部工作在基座2,但结果打印在基座10中,因此需要从基座2到基座10的转换。即使您可以打印任意数量的浮点数,也不会使其比内部精度更准确。在C中演示,打印1.1最多15位数字:

#include <stdio.h>

int main(int argc, char** argv) {
  float x = 1.1;
  printf("x = %.15f\n", x);
}

此程序打印

x = 1.100000023841858

在我的机器上。由于浮点数有7位有效数字,因此第7位数之后的所有内容都应被视为垃圾。如您所见,它垃圾。

在您的示例中计算float out = in-floor(in);并且丢失了7位数中的4位之后,您应该只打印最多3位数的结果,这是您的责任。最多3个有效数字0.44995117 0.450这是你所期待的。

答案 1 :(得分:2)

当然最好只使用out = in % 1;,这适用于正面或负面in

答案 2 :(得分:1)

肯定in

out = in - (float) floor(in)

否定in

out = in - (float) ceil(in)