double在c语言中如何运算,关于数学:如何计算double / float C ++中的位数

我正在尝试计算double的小数部分的位数,但是出现了问题,并且出现了无限循环:

double pi = 3.141592;

int counter = 0;

for (; pi != int(pi); ++counter)

pi *= 10;

cout << counter << endl;

我刚刚读过这个问题,但是找不到很好的解决方案。 真的没有比将数字转换为字符串并计算字符更好的方法了吗? 我想有更正确的方法。

在每个步骤中打印出pi值并亲自查看

浮点数中几乎没有数字位数。 有这样的事情精度。

binaryconvert.com/-特别注意:"最准确的表示= 3.14159200000000016217427400989E0"

@drorco其到此帖子的链接)

好吧,代码在我的机器上工作正常

相关/重复:stackoverflow.com/questions/1083304/

@RajeevSingh,这是我的错,我在代码和pi中有另一个数字作为示例。 尝试3.1415,它将无法正常工作

计算机中的浮点数使用二进制(基数2,零和一,就像计算机中几乎所有数字一样)。因此,它们中有确切数目的二进制数字,double中更多,而float中更少。但是,如果将3.141592之类的十进制常量转换为double,然后以完全正确的精度进行打印,则不会得到相同的数字。这是因为一般而言,在基数之间转换小数位并不精确(与1/3具有无限小数扩展0.33 ...时获得的效果相似)。例:

double pi = 3.141592;

std::cout << std::setprecision(100) << pi << std::endl;

输出给我:

3.14159200000000016217427400988526642322540283203125

因此,当您在问题代码中开始将其乘以10时,您会看到它在很长一段时间内不会变成精确的整数(到那时它已经远远超出了int的范围),因此您的条件永远不会成立(要么是小数部分,要么是双数太大而无法容纳整数)。

换句话说,直接从double计算数字的要求是没有意义的。首先,您需要将其打印为字符串,否则,您实际上并没有要计数的十进制数。当然,您可以对此进行微优化,并跳过实际转换为ASCII或UTF-16字符串的操作,但是我看不到会有这种麻烦的情况(除非作为学习练习)。

如果在计算中需要精确的十进制数字,则需要一种特殊的数字类型,该类型不以二进制形式存储小数。此类数字类型的示例是Java BigDecimal。

你确定你实际上可以得到与基2浮点值无限扩张? 我非常确定您不能,并且可能会为此提供证明(或只是在互联网上找到一个证明...)。(推理将遵循" Base-2小数是2^-n的和) 每个n具有有限的10进制表示,因此总和也必须具有有限的数字。")

@anderas编辑...

粗糙的是无限循环

当您将浮点变量与小数部分相乘时,某些数字在FPU算术上往往表现得不合理(由于舍入误差)。因此,无论您乘以10多少,仍然会有一些小数部分...

怎么做呢

您需要改为以二进制形式查看尾数,并查看最低有效设置位在哪里。所以:

union

{

double lf;

BYTE db[8];

} pi;

pi.lf = 3.141592;

// here just output the BYTES to memo,screen or whatever

mm_log->Lines->Add(AnsiString().sprintf("%x",pi.db[0])); // LSB

mm_log->Lines->Add(AnsiString().sprintf("%x",pi.db[1]));

mm_log->Lines->Add(AnsiString().sprintf("%x",pi.db[2]));

mm_log->Lines->Add(AnsiString().sprintf("%x",pi.db[3]));

mm_log->Lines->Add(AnsiString().sprintf("%x",pi.db[4]));

mm_log->Lines->Add(AnsiString().sprintf("%x",pi.db[5]));

mm_log->Lines->Add(AnsiString().sprintf("%x",pi.db[6]));

mm_log->Lines->Add(AnsiString().sprintf("%x",pi.db[7])); // MSB

结果是pi被存储为:

0x400921FAFC8B007A hex

0100 0000 0000 1001 0010 0001 1111 1010 1111 1100 1000 1011 0000 0000 0111 1010 bin

根据Wiki IEEE_754,双重划分如下:

sign     = 0 bin -> +

exponent = 100 0000 0000 bin - 1023 dec = 1

mantissa = 1.1001 0010 0001 1111 1010 1111 1100 1000 1011 0000 0000 0111 1010 bin

请注意,尾数添加了1.,它在数字表示形式!!!中不存在。指数也是有偏的,这就是为什么-1023存在的原因。现在,当应用指数左移后,我们得到

pi = 11.001 0010 0001 1111 1010 1111 1100 1000 1011 0000 0000 0111 1010 bin

现在我们寻找最少设置的有效位

pi = 11.001 0010 0001 1111 1010 1111 1100 1000 1011 0000 0000 0111 1010 bin

^

它的重量为2^-50=1/2^50=8.8817841970012523233890533447266e-16=~10e-16(小数点后第50位),这意味着您获得了约16个十进制数的pi=3.141592十进制数。正确打印后,您将看到:

3.14159200000000016

您也可以使用n10=~log10(n2)估算由n2二进制小数表示的十进制十进制n10的数量。但是对于低n2来说有点不规则。有关更多信息,请参见

如何打印浮点数的EXACT值?

从n2=50开始的是n10=15,非常接近该~16小数。这意味着如果仅存在安全的十进制数字,则应将3.14159200000000016截断为3.141592000000000。

num = pi - int(pi);

while abs(num) >= 0.0000001{

num = num * 10;

count = count + 1;

num = num - int(num);

}

cout<< count<< endl;

有关更多信息,您可以阅读此C / C ++计算小数位数?。

Atharva MR Fire在这里。

我做了一个简单的函数,可以计算双精度位数(浮点数为8位,因此只需将16更改为8并进行其他必要的更改即可。)

int get_float_digits(double num)

{

int digits=0;

double ori=num;//storing original number

long num2=num;

while(num2>0)//count no of digits before floating point

{

digits++;

num2=num2/10;

}

if(ori==0)

digits=1;

num=ori;

double no_float;

no_float=ori*(pow(10, (16-digits)));

long long int total=(long long int)no_float;

int no_of_digits, extrazeroes=0;

for(int i=0; i<16; i++)

{

int dig;

dig=total%10;

total=total/10;

if(dig!=0)

break;

else

extrazeroes++;

}

no_of_digits=16-extrazeroes;

return no_of_digits;

}

如果只想获取小数位数,请在返回函数之前的末尾添加代码no_of_digits=no_of_digits-digits;。

我希望这有帮助。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值