C 反转长双精度的指数会给我一个疯狂的结果

C 反转长双精度的指数会给我一个疯狂的结果,c,floating-point,fractions,exponent,long-double,C,Floating Point,Fractions,Exponent,Long Double,我试图反转长双精度的指数 假设x=3.5e1356。我希望x是3.5e-1356 我有以下代码: long double x = 3.5e1356L; int exponent; long double fraction = frexpl(x, &exponent); // recreate number with an inverted exponent long double newNumber = ldexpl(fraction, -exponent); 此代码后的新编号为1

我试图反转长双精度的指数

假设x=3.5e1356。我希望x是3.5e-1356

我有以下代码:

long double x = 3.5e1356L;
int exponent;
long double fraction = frexpl(x, &exponent);

// recreate number with an inverted exponent
long double newNumber =  ldexpl(fraction, -exponent);
此代码后的新编号为1.14732677619641872902e-1357

那与原来的号码无关


我错过了什么?

你倒了指数,但指数一开始就不是1356。长双精度的指数是它的二元指数

您可能编写了3.5*10^1356,但在内部,计算机将其存储为*2^其他内容。你所做的是生产一些*2^-其他的东西,而不是3.5*10^-1356*

如果你想得到3.5*10^-1356,你可能需要用以10为底的对数来实现它


*frexpl使用的规范化约定与您的计算机可能使用的规范化约定不同,因此它不是完全反转机器级指数,而是反转二进制指数,而不是您编写的十进制指数。

基于你们的帮助,我创建了这段代码,它可以工作,但可能可以改进

  NSInteger exponent = 0;
  long double remainder = x;

  // stop the loop if remainder is >= 1 and less than 10
  while (!((fabsl(remainder) >= 1.0L) && (fabsl(remainder) < 10.0L))) {
    remainder /= 10.0L;
    exponent ++;
  }

  long double finalNumber =  remainder * powl(10.0L, -exponent);
利用以下事实:

a * (10^n) * (10^m) = a * 10^(n+m) 
如果你计算m,使之为-2n,你会得到:

a * (10^n) * (10^-2n) = a * 10^(n+(-2n)) =  a * 10^-n
换言之,只需将原始数字乘以10^-2n即可

我想试试这样的东西:

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

int main(void) {
    long double x = 8.9e-100;
    long double y = 0.0;
    int exp10;

    if (x != 0.0)
    {
        exp10 = log10l(fabsl(x));
        exp10 = (exp10 >= 0) ? -2*exp10 : -2*(exp10-1);
        y = x * powl(10, exp10);
    }

    printf("%.36Le\n", x);
    printf("%.36Le\n", y);

    return 0;
}

指数是二进制的,而不是十进制的。请尝试查看实现定义的LDBL_MAX和LDBL_MIN值,即长双精度可以分别表示的最大正值和最小正值。即使是LDBL_MAX的典型值也不超过1E308,而且您的输入值比这个值大得多,所以可能会溢出。一旦发生这种情况,行为就没有定义。需要记住的基本事项:浮点表示不能表示任意大小的值。@彼得:在英特尔硬件上,长双精度有一个16位指数,允许比1E308大得多的数字。@彼得:浮点要求非常保守。OP中的值肯定远远超出了最低要求。但是80位长的double是一种非常常见的实现,它可以追溯到80387 FP协处理器,并且有理由猜测,不需要解释他们正在使用不寻常的硬件的人实际上是在一个具有80位长double的平台上。我不得不问-为什么?你的实验室,2712的10次方在实验误差范围内吗?好的,我现在明白了,但请用答案来说明问题的解决方案,而不是指出问题所在。谢谢我可以想象一个蹩脚的解决方案,其中我创建了一个循环,将x除以10,然后计算除数,直到余数大于等于1且小于10。如果有更好的方法,请解释。@SpaceDog:你知道吗?好的,我可以用它来发现指数,但看看我的答案。。。我看不出这有什么帮助。抱歉,我的大脑没有看到…除法循环会失去精度,而且效率低下,没有什么好的理由,请使用log10l。完美的,我的循环解决方案也很好,但可能会随着循环的进行而失去精度,正如Mateo指出的那样。您在这一行中使用的方法exp10=exp10>=0-2*exp10:-2*exp10-1;,将整个事物乘以相反的东西,这很有趣。感谢可能并不完美。角盒:exp10=log10lfabslx;当x==0.0.exp10=exp10>=0时出现问题-2*exp10:-2*exp10-1;y=x*powl10,exp10;招致不必要的溢出。。可以使用两个步骤:exp10=exp10>=0-exp10:-exp10-1;y=x*powl10,exp10*powl10,exp10;
3.5 * 10^12 * 10^-24 --> 3.5 * 10^-12