【问题标题】:Getting the fractional part of a double value in integer without losing precision以整数形式获取双精度值的小数部分而不会丢失精度
【发布时间】:2013-06-20 00:08:34
【问题描述】:

我想将精度高达 4 位的双精度值的小数部分转换为整数。但是当我这样做时,我会失去精度。有什么办法可以让我得到精确的值吗?

#include<stdio.h>
int main()
{
    double number;
    double fractional_part;
    int output;
    number = 1.1234;
    fractional_part = number-(int)number;
    fractional_part = fractional_part*10000.0;
    printf("%lf\n",fractional_part);
    output = (int)fractional_part;
    printf("%d\n",output);
    return 0;
}

我期望输出为 1234,但它给出了 1233。请提出一种方法,以便我可以获得所需的输出。我想要C语言的解决方案。

【问题讨论】:

  • 您只是在同一个句子中使用了“double”或“float”和“precise value”这两个词。糟糕的魔力。你的方法没问题,但在转换为 int 之前添加 0.5,因为这可能是截断而不是四舍五入。更好的是,明确使用 round()。这将为您提供最接近的价值。 "The" 精确值不存在。

标签: c double type-conversion precision floating


【解决方案1】:

使用modf 和 ceil

#include <stdio.h>
#include <math.h>

int main(void)
{
    double param, fractpart, intpart;
    int output;

    param = 1.1234;
    fractpart = modf(param , &intpart);
    output = (int)(ceil(fractpart * 10000));
    printf("%d\n", output);

    return 0;
}

【讨论】:

  • 他想要一个整数。他的乘法和舍入方法很好,他只需要更接近而不是截断。
  • @David RF,当我输入 1.0500 时,我预计输出为 500,但它显示 501,我认为 ceil 并非在所有情况下都有效。
  • 阿图尔,是的,然后再给精度一位数并除以 10 output = (int)(ceil(fractpart * 100000)) / 10;
【解决方案2】:

假设即使对于负值,您也想获得正分数,我会选择

(int)round(fabs(value - trunc(value)) * 1e4)

这应该会给你预期的结果1234

如果你不四舍五入,只是截断值

(int)(fabs(value - trunc(value)) * 1e4)

(本质上与您的原始代码相同),您最终会得到意想不到的结果 1233 as 1.1234 - 1.0 = 0.12339999999999995 双精度。

不使用round(),将操作顺序改为

(int)(fabs(value * 1e4 - trunc(value) * 1e4))

如果value 的整数部分足够大,浮点不准确当然会再次出现。

您也可以使用 modf() 而不是 David 建议的 trunc(),这可能是浮点精度的最佳方法:

double dummy;
(int)round(fabs(modf(value, &dummy)) * 1e4)

【讨论】:

  • @DavidRF:第一个版本将返回预期的1234;由于浮点语义,第二个返回1233;我会更新答案...
  • 这些并不总是产生正确的答案。截断不会,因为问题中的示例显示1.1234 需要 1234,但截断会产生 1233。对于舍入,请考虑值 0.10264999999999999912514425659537664614617824554443359375。那么小数的前四位十进制数字是 1026。但是当使用 double 算术(IEEE 754 64 位二进制)时,舍入方法会产生 1027。
  • @EricPostpischil: 0.1026499999999999912514425659537664614617824554443359375 和 0.10265 就双精度而言是相同的数字,因为它们仅在第 56 个二进制数字上有所不同(尽管有一个错误);由于双打的 53 位限制,人们只需要接受有些事情是不可能的......
  • @EricPostpischil:我明白你的观点,如果 Atul 想要截断,使用 round() 不一定会做正确的事情(他没有在他的回答中指定,所以声称我的回答是错误的有点过早);如果截断确实是他想要的,我相信您将不得不与nextafter() 混在一起并在模棱两可的情况下掷硬币......
  • @Christoph:是的,有问题。不,它不是无解的。有一篇广为人知的论文,Correctly Rounded Binary-Decimal and Decimal-Binary Conversions by David M. Gay。这个答案提供了产生不正确结果的代码。获得正确结果的方法是已知的并已公布。如果你想要一个快速而简单的解决方案并且有一个良好的 C 实现,你可以使用sprintf 将浮点数转换为十进制,scanf 转换为整数。
【解决方案3】:

数字= 1.1234,整数=1,分数=1234

int main()
{
 double number;
 int whole, fraction;
 number = 1.1234;
 whole= (int)number;
 fraction =(int)(number*10000);
 fraction = fraction-(whole *10000);
 printf("%d\n",fraction);
 printf("%d\n",whole);
 return 0;
}

【讨论】:

  • 我同意你的例子。但是如果我不知道数字,也不知道小数部分有多大?
  • @RemusAvram 检查此代码然后stackoverflow.com/a/18517555/2508414 对我们来说很好,代码应该可以正常工作,如果我们尝试为一个非常大的数字编写代码(据我所知)没有答案..那些做研究和高水平编程的人可以做到。但到目前为止,我还没有找到比我实现的更好的逻辑。
【解决方案4】:

任何数字的解决方案可能是:

#include <cmath>

using namespace std;

int _tmain(int argc, _TCHAR* argv[])

{ 
float number = 123.46244;
float number_final;
float temp = number;  // keep the number in a temporary variable
int temp2 = 1;        // keep the length of the fractional part

while (fmod(temp, 10) !=0)   // find the length of the fractional part
{
    temp = temp*10;
    temp2 *= 10;
}

temp /= 10;       // in tins step our number is lile this xxxx0
temp2 /= 10;
number_final = fmod(temp, temp2);

cout<<number_final;

getch();
return 0;
}

【讨论】:

    猜你喜欢
    • 2013-06-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-10-02
    • 1970-01-01
    • 1970-01-01
    • 2021-04-24
    • 1970-01-01
    相关资源
    最近更新 更多