2017-07-15 54 views
-4

我想反转长双的指数。反转长双的指数给我一个疯狂的结果

假设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); 

此代码后newNumber1.14732677619641872902e-1357

有无关原来的号码。

我错过了什么?

+5

指数是二进制,而不是小数。 – user2357112

+0

尝试查看LDBL_MAX和LDBL_MIN的(实现定义的)值(long double可分别表示最大和最小正值)。即使“LDBL_MAX”的“典型”值不超过“1E308”,并且您的输入值比这大得多 - 因此可能会溢出。一旦发生这种情况,行为是不确定的。基本的事情要记住:浮点表示不能表示任何数量级的任意值。 – Peter

+1

@peter:在英特尔硬件上,long double具有16位指数,这允许比1E308大得多的数字。 – rici

回答

1

使用的事实,

a * (10^n) * (10^m) = a * 10^(n+m) 

如果计算米,所以它是-2你会得到:

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; 
} 

例为3.5×10^12:

3.5 * 10^12 * 10^-24 --> 3.5 * 10^-12 
+1

完美的是,我的循环解决方案运作良好,但循环可能会失去精确性,正如Mateo指出的那样。你在这行上使用的方法exp10 =(exp10> = 0)? -2 * exp10:-2 *(exp10-1);',将整个事物乘以相反,这很有趣。谢谢 – SpaceDog

+0

也许不完美。案例:'exp10 = log10l(fabsl(x));''x == 0.0时有问题。 – chux

+0

'exp10 =(exp10> = 0)? -2 * exp10:-2 *(exp10-1); y = x * powl(10,exp10);'请不必要的溢出..可以使用2个步骤:'exp10 =(exp10> = 0)? -exp10: - (exp10-1); y = x * powl(10,exp10)* powl(10,exp10);' – chux

3

你已经颠倒了指数,但指数从来没有1356在第一位。长整数的指数是二进制指数。

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

如果您想获得3.5 * 10^-1356,您可能需要以10对数为底数来实现它。

* frexpl使用比您的计算机可能使用不同的正常化惯例,所以它不是很倒置机器级指数,但它反转二进制指数,而不是你写小数点之一。

+0

好吧,我现在明白了,但请使用答案来显示问题的解决方案,而不是指出什么是错的。谢谢。我可以想象一个蹩脚的解决方案,我创建一个循环,将x除以10,并计算除数,直到余数大于等于1且小于等于10.如果有更好的东西,请解释。 – SpaceDog

+1

@SpaceDog:你知道['log10l'](http://en.cppreference.com/w/c/numeric/math/log10)吗? – user2357112

+0

好的我可以使用它来发现指数,但看到我的答案...我没有看到这可以帮助那里。对不起,我的大脑没有看到... – SpaceDog

0

基于从你们那里,我创造了这个代码,该代码工作,但大概可以提高帮助...

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); 
+4

这个分割循环失去了精度,没有很好的理由效率低下,使用'log10l'。 –