2017-07-15 45 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'。 –