Nth root of small number return an unexpected result in C#

Asked
Viewd5356

5

When I try to take the N th root of a small number using C# I get a wrong number.

For example, when I try to take the third root of 1.07, I get 1, which is clearly not true.

Here is the exact code I am using to get the third root.

MessageBox.Show(Math.Pow(1.07,(1/3)).toString());

How do I solve this problem?

I would guess that this is a floating point arithmetic issue, but I don't know how to handle it.

  • It’s actually an integer division problem. 1/3 is evaluated as integers with the result of the division being 0. Thus you are really taking 1.07 to the 0th power which is 1.

    tvanfosson10 октября 2009, 02:06

4 ответов

9

Я почти уверен, что указанный вами "точный код" не компилируется.

 MessageBox.Show(Math.Pow(1.07,(1/3).toString()));
 

Вызов toString находится на неправильном уровне вложенности, должен быть ToString, а (1/3) - целочисленное деление, что, вероятно, является реальной проблемой, с которой вы столкнулись. (1/3) равно 0, а любая нулевая степень равна 1. Вам нужно использовать (1.0 / 3.0) или (1d / 3d) или ...

  • Обычно я бы не стал указывать на очевидную синтаксическую ошибку, но почему-то чувствовал себя обязанным, поскольку вы потрудились использовать слово «точный». Рад, что помог.

    I. J. Kennedy10 октября 2009, 05:40
  • Dear captain sarcastic. Sorry about the misplaced ). I should have copied and pasted instead of retyping. I have now corrected the info. Thank you for the excellent answer!

    JK.10 октября 2009, 02:51
13

C # рассматривает 1 и 3 как целые числа, вам необходимо сделать следующее:

 Math.Pow(1.07,(1d/3d))
 

или

 Math.Pow(1.07,(1.0/3.0))
 

Это действительно интересно, потому что неявное расширяющее преобразование заставляет вас совершить ошибку.

1

Это может помочь в случае, если у вас есть реальная проблема точности корня n-й степени, но я считаю, что встроенный Math.Pow (double, int) более точен:

     private static decimal NthRoot(decimal baseValue, int N)
    {
        if (N == 1)
            return baseValue;
        decimal deltaX;
        decimal x = 1M;
        do
        {
            deltaX = (baseValue / Pow(x, N - 1) - x) / N;
            x = x + deltaX;
        } while (Math.Abs(deltaX) > 0);
        return x;
    }

    private static decimal Pow(decimal a, int b)
    {
        if (b == 0) return 1;
        if (a == 0) return 0;
        if (b == 1) return a;
        if (b % 2 == 0)
            return Pow(a * a, b / 2);
        else if (b % 2 == 1)
            return a * Pow(a * a, b / 2);
        return 0;
    }
 
3

Перво-наперво: если вы используете именно такой код, вероятно, что-то не так с вашим компилятором :-)

 MessageBox.Show(Math.Pow(1.07,(1/3).toString()));
 

сначала оценит (1/3) .toString (), а затем попытается возвести 1,07 в степень этой строки.

Думаю, вы имеете в виду:

 MessageBox.Show(Math.Pow(1.07,(1/3)).ToString());
 

Что касается проблемы, (1/3) обрабатывается как целочисленное деление, возвращающее 0, а n 0 равно 1 для всех значений n.

Вам нужно заставить его деление с плавающей запятой, например, 1.0/3.0.

  • Извините за неуместное). Я должен был скопировать и вставить вместо того, чтобы перепечатывать. Я исправил информацию.

    JK.10 октября 2009, 02:50