Инвертирование степени длинного двойного дает мне безумный результат

Я пытаюсь инвертировать показатель длинной двойной.

Предположим, что x = 3.5e1356. Я хочу, чтобы х было 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);

после этого кода, newNumber является 1.14732677619641872902e-1357

это не имеет ничего общего с оригинальным номером.

Что мне не хватает?

3 ответа

Решение

Используйте тот факт, что

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

Пример для 3.5 * 10^12:

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

Вы инвертировали показатель степени, но показатель никогда не был 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);
Другие вопросы по тегам