Решил я намедни сделать для себя небольшой, но очень удобный велосипед для вычисления всяких полезных математических функций. Стоит отметить, что пишу я на разных языках, и в этот раз выбор пал на C++. Пилю я, значит, сей чудесный трехколесный транспорт и параллельно занимаюсь юнит-тестированием свежесозданных функций… И тут нате-здрасте — один из тестов выдает мне совсем не тот результат, которого я ждал. Готовы?!
Ноль в степени ноль равен единице!!! (многозначительный трагический взгляд)
Ну, думаю, бывает всякое и разное. Решил проверить функцию pow() отдельно, наивно полагая, что словлю хотя бы исключение:
#include <cmath> #include <iostream> #include <stdexcept> int main(void) { try { std::cout << "zero at degree zero: " << std::pow(0, 0) << std::endl; } catch(std::exception &ex) { std::cerr << ex.what() << std::endl; } return 0; }
Ожидания подтвердились — никаких исключений (все в полном соответствии с документацией), результат в консоли — упорная единица.
Позволю себе небольшое отступление на минутку науки. Если совсем коротко и упрощенно, то:
Возведение в степень — бинарная операция, при которой число a умножается само на себя столько раз, сколько указано в показателе степени b. Записывается это как ab и читается "a в степени b". Например:
35 = 3*3*3*3*3 или 52 = 5*5
Но как быть, если показатель степени равен нулю? Как должна выглядеть запись после знака равенства?.. Решение оказалось довольно простым — в силу свойств степени, число ab можно представить в виде ab = ac * a(b-c). Для наглядности:
47 = (4*4*4)*(4*4*4*4) = 43 * 44
Число же в нулевой степени можно представить как a0 = ab * a-b. Но что это за отрицательная степень такая, как понимать? Ответ довольно прост: действие, обратное умножению — деление. Так, число в отрицательной степени означает единицу, деленную на число в положительной степени — a-b = 1/ab.
Исходя из вышенаписанного, мы можем сделать довольно простой вывод:
a0 = ab * a-b = ab/ab = 1
Но как быть в случае, если a = 0? Возникает довольно неприятная ситуация — деление нуля на ноль, на который делить строго запрещено под страхом возникновения сверхмассивных черных дыр.
Есть и другие способы вычисления нуля в нулевой степени и одни дают единицу, другие ноль, третьи опять деление на ноль. Такая ситуация, когда что-то не поддается вычислению, в математике называется неопределенностью (нельзя определить однозначно).
Ну вот, кратенький ликбез закончен.
Теперь вернемся снова к программированию… Решил я проверить как дела обстоят в других языках и запустил Python:
import math try: print("0**0:", 0**0) print("pow(0, 0)", math.pow(0, 0)) except: print("Exception")
И этот змей выдает единицу и никаких ошибок. Да что ж такое-то?! Полез в эти ваши интернеты и наткнулся на вот такой список. Вот ведь подсуропили нам ребятки — почти во всех языках выдается единица, вместо ожидаемой ошибки, как, например, при делении на ноль.
И такое встречается в браузерных калькуляторах той же корпорации добра, яндекса, стандартных системных. И это, по моему скромному мнению, чертовски серьезная ошибка. Поэтому, не удивляйтесь, когда увидите в коде:
T correct_pow(T a, T b) { if(a == 0 && b == 0) { throw std:: } return(pow(a, b));
ссылка на оригинал статьи https://habrahabr.ru/post/278971/
Добавить комментарий