Расчет мощности с двойными числами дает неверные результаты

Я программирую калькулятор на Arduino, пытаюсь вычислить мощность и записать ее в строку (результат). Это мой код:

dtostrf(exp(n*log(x)), 0, 5, result); // x ^ n

2 ^ 2 = 4.00000 // works fine

10 ^ 5 = 99999.9770 // should be 100000

Что не так с моим кодом и как я всегда могу получить правильный результат? Я имею в виду, как я могу округлить его, но все же иметь возможность использовать двойные (например, 5,2 ^ 3,123)


person Akim Wright    schedule 23.11.2014    source источник
comment
docs.oracle.com/cd/E19957-01/806- 3568 / ncg_goldberg.html   -  person deviantfan    schedule 23.11.2014
comment
См. Ответы на этот вопрос.   -  person jolati    schedule 23.11.2014
comment
Arduino Uno имеет очень простой процессор без поддержки операций с плавающей запятой. Следствием этого является то, что double вообще не является двойной точностью, он занимает 4 байта и эмулируется в программном обеспечении с одинарной точностью. Потеря точности, конечно, неизбежна, вы никогда не можете рассчитывать на более чем 6 точных цифр. Поиск решений для подобных проблем - вот чем занимаются энтузиасты Arduino.   -  person Hans Passant    schedule 23.11.2014
comment
Хорошо, это означает, что я могу использовать числа с плавающей запятой вместо удвоений?   -  person Akim Wright    schedule 23.11.2014
comment
Нет, float тоже 4 байта. В случае выполнения double даст большую точность, чем float; на Uno они будут такими же. float никогда не будет иметь большей точности, чем double.   -  person chiastic-security    schedule 23.11.2014
comment
Во встроенных системах реального времени ЦП без модуля с плавающей запятой были довольно распространены, по крайней мере, в начале 90-х годов. К счастью, в настоящее время большинство процессоров имеют числа с плавающей запятой, а многие также имеют векторные единицы. Поскольку ваш процессор этого не делает, вы можете вернуться к таким методам, как Newton-Raphson, я видел, что они используются в системах реального времени для вычислений, например. квадратные корни на процессорах, которые имеют только целочисленную арифметику. Возможно, вы могли бы сделать что-то подобное для pow ().   -  person Erik Alapää    schedule 23.11.2014


Ответы (2)


Вы просто сталкиваетесь с ошибками округления. Вы ничего не можете с этим поделать, кроме как вернуться к целочисленному подходу, когда входные данные являются целыми числами.

Вы можете указать, являются ли входные данные целыми числами, и если да, то используйте целочисленную арифметику; если нет, то используйте двойные. Но использование exp и log всегда будет приводить к ошибкам округления, поэтому вы не можете ожидать точных ответов при таком подходе.

Точнее, чтобы использовать целочисленную арифметику, вам нужно, чтобы основание было целым числом, а показатель степени - неотрицательным целым числом.

person chiastic-security    schedule 23.11.2014
comment
Хорошо, но как калькуляторы могут получить правильный результат при использовании удвоения? - person Akim Wright; 23.11.2014
comment
@AkimWright Я подозреваю, что они также используют целочисленную арифметику, когда вводятся целые числа. - person chiastic-security; 23.11.2014
comment
Хорошо, мой код теперь проверяет, если floor (x) == x && floor (n) == n. Работает очень хорошо - person Akim Wright; 23.11.2014

Поскольку вы программируете калькулятор, вас беспокоит не скорость, а количество надежных цифр. Итак, вы можете попробовать использовать библиотеку двойной точности. Он использует 64-битные удвоения, но имеет всего около 200 FLOPS при тактовой частоте процессора 16 МГц и намного меньше при вычислениях более высокого порядка, таких как exp (), log () или sin (). Таким образом, после ввода цифр и нажатия кнопки ввода потребуется секунда, но так было и со старыми 8-битными карманными счетчиками.

См. Эту ссылку (только на немецком языке)

person Hartmut Pfitzinger    schedule 24.11.2014