【问题标题】:How to get the exact fractional part from a floating point number as an integer?如何从浮点数中获取精确的小数部分作为整数?
【发布时间】:2015-12-18 17:48:13
【问题描述】:

我试图从浮点数中提取精确的小数部分。我试过这个:

float f=254.73;

int integer = (int)f;
float fractional = f-integer;

printf ("The fractional part is: %f", fractional);

但输出是:0.729996。出于这个原因,当我这样做时:

float f=254.73;

int integer = (int)f;
float fractional = f-integer;
int fractional_part_in_integer = ((int)(f*100)%100);

printf ("The value is: %d", fractional_part_in_integer);

它给了我72 作为输出。但是,我想从给定的数字254.73 中准确提取73。我已经知道如何在printf() 函数中使用%.2f 打印最多两个十进制数字。但在我的代码中,我现在不想打印这个数字。我有一些以小数部分为整数形式的计算,即73

那么,我的问题是如何从254.73 中提取小数部分,以便我可以得到精确的73 作为整数来进行更多计算?

【问题讨论】:

  • 浮点数不能表示为您希望它们大部分时间的精确值。你的结果是合理的。一个可能很有趣的实验是打印f 的值,它可能只接近你的想法(虽然我自己并不累,所以我不确定)。更新:我试过了:ideone.com/9fbeme
  • 谢谢。但是,我希望应该有一种方法可以在那里用 73 进行一些其他计算。更新:是的,我已经这样做了,并得到了你在实验中发现的价值。
  • 由于您的硬件不能准确地表示 254.73,您将不得不找到一些其他硬件,或者使用基于整数的计算来代替(例如使用 25473 并稍后除以 100 )。
  • 如果您的意思是“如何获得 .73”,如果您的硬件无法代表它,您将永远无法获得准确的值。但是,您可以将原始值(以及您使用的所有其他值)乘以 100,在此级别使用它们(表示正好是您需要的值的 100 倍),然后除以 100 以获得您的确切的结果(仍然受限于您的硬件可以表示的内容)。
  • @RakibulIslam 既然我理解了你试图更好地解决的问题,我认为你最好的选择是按照 user3121023 建议的方式拆分 string 数据在他的回答中。这将为您提供两个整数值,254 和 73,然后您可以按照您似乎已经在做的方式处理它们。只需将“部分美元”值处理为整数(您希望在 0 到 99 之间)而不是浮点值。

标签: c floating-point


【解决方案1】:

如何将浮点数作为整数得到精确的小数部分?

试图从浮点数中提取精确的小数部分。

使用modf()modff()

double modf(double value, double *iptr);
float modff(float value, float *iptr);

modf 函数将参数值分解为整数和小数部分,...
C11 §7.12.6.12 2

#include <math.h>

double value = 1.234;
double ipart;
double frac = modf(value, &ipart);

满足 OP 需求的更好方法可能是首先对一个缩放值进行四舍五入,然后再返回整数和小数部分。

double value = 254.73;
value = round(value*100.0);
 
double frac = fmod(value, 100);  // fmod computes the floating-point remainder of x/y.
double ipart = (value - frac)/100.0;

printf("%f %f\n", ipart, frac);
254.000000 73.000000

参考细节:当 OP 使用 254.73 时,这将转换为最接近的 float 值,可能是 254.729995727539...

float f = 254.73;
printf("%.30f\n", f);
// 254.729995727539062500000000000000

【讨论】:

  • 这不会产生与 OP 已经获得的结果相同的结果吗?
  • @mah。不,当f 超出int 范围时,OP 的方法对(int)f ; fractional = f-integer; 有问题,2)f 为负数 3)int 的精度低于f。 OP 的第二种方法可能会给出不令人满意的结果,例如 1.99999
  • 不检查但只考虑您的推理,我相信您的特定用例是使用您的fmod() 建议的正当理由...但考虑到 OP 使用的实际值 254.73,除非您建议解决了他的困境(即:他希望得到 0.73,而不是 0.7299996),我认为你的帖子是一个很好的评论,但不是一个答案。我愿意被展示为什么我可能是错的。
  • @mah 不期望0.73。 OP 期待 73。 “小数部分为整数形式,即 73。”返工第二种方法。
【解决方案2】:

您可以使用 sprintf 和 sscanf 将值打印到字符串,然后提取分数。 %*d 扫描并丢弃格式化字符串的第一个整数。扫描一个点,然后扫描分数。

#include <stdio.h>        

int main( void)           
{                         
    char fp[30];          
    int fraction;         
    float f = 254.73f;    

    sprintf ( fp, "%.2f", f);
    sscanf ( fp, "%*d.%d", &fraction);
    printf ( "%d\n", fraction);

    return 0;                  
}

【讨论】:

  • 1) 此方法仅提取小数部分(根据 OP 的要求),但输入值如 123.996,代码将为小数呈现 0,并且不清楚整个部分将如何递增到124. 2)char fp[30];可能太小,建议char fp[FLT_MAX_10_EXP + 6];
【解决方案3】:

最简单的方法是使用来自&lt;math.h&gt; 的标准库函数ceil
float 数字 254.73 可以转换为 254.7299957275390625000000
f-integer 将得到 0.7299957275390625000000
现在将它乘以100 并使用ceil 函数得到不小于72.99957275390625000000 的最小整数值。

int fractional_part_in_integer = ((int)ceil(fractional*100)) % 100;

更新: 正如@Sneftelcomment 中指出的那样,此答案中的上述建议方法将无法始终如一地工作。

一个简单的hack是使用math.h中的round函数对f进行四舍五入,然后提取小数部分

float f=254.73;

int int_part = (int)f;
float fractional = round(f*100)/100 - int_part;
int fractional_part_in_integer = (int)(fractional*100);

printf("%d, %d\n ", int_part, fractional_part_in_integer);

输出:

254, 73

【讨论】:

  • ceil函数的签名是double ceil(double x);。它计算不小于x 的最小整数值并返回⎡x⎤。不要忘记包含#include &lt;math.h&gt;
  • ceil() 产生的数字也可能是 1。
  • @Sneftel;我认为您正在谈论的是floor。顺便说一句,这是我的解决方案的demo
  • @hacks 是吗?试试this oneceilfloor 都不会始终如一地工作,因为该值可能略低于 0.01 的倍数,也可能略高于它。
  • @Sneftel;你说的对。我更新了我的答案。现在是fixed
【解决方案4】:

取字符串中的数字,使用内置函数find()查找“.”的位置.

#include <iostream>
using namespace std;

int main()
{    
    string f = "254.7356656";    
    int position = f.find(".");    
    cout << f.substr(position + 1);    
    return 0;    
}

输出:7356656

【讨论】:

  • 在 Stack Overflow 上的回答中推荐使用 #include &lt;bits/stdc++.h&gt; 是要求投反对票;请改用所需的 standard 头文件。见:stackoverflow.com/q/31816095/10871073
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-05-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多