Операция на переменную и константу, дающую разный результат в с - PullRequest
0 голосов
/ 19 ноября 2018

Простой расчет: 3 ^ 20% 15.Ответ, согласно калькулятору, равен 6.

Следующий код генерирует ответ 7.

#include <stdio.h>
#include <math.h>
int main() {
        int i = 20;
        printf("%d\n", ((int)pow(3,20)%15));
        return 0;
}

Если я заменим 20 в операторе printf на переменную i, он выдает -8 в качестве вывода.

Если предположить, что калькулятор работает (или нет), в чем проблема в программе?

Спасибо.

Ответы [ 2 ]

0 голосов
/ 19 ноября 2018

Вероятно, что здесь произошло:

  • В вашей реализации C int составляет 32 бита, с минимальным значением –2 147 483 648 и максимальным значением 2 147 483 647.
  • Результатpow(3, 20) равно 3486784401. (См. примечание 1 ниже.)
  • 3486784401 слишком велико для int, поэтому имеется переполнение.В случае целочисленного переполнения стандарт C позволяет реализации делать что угодно.
  • В (int) pow(3, 20) преобразование в int могло быть вычислено во время компиляции путем получения максимума, 2 147 483 647.Тогда остаток от этого, разделенного на 15, равен 7.
  • В (int) pow(3, i) преобразование в int могло быть вычислено во время выполнения с получением минимального значения -2 147 483 648.(Некоторые процессоры выдают такой результат для целочисленных переполнений.) Тогда остаток от деления на 15 равен -8.

В итоге:

  • Ваш код переполняется, поэтомустандарт C не определяет поведение.
  • Компилятор, вероятно, ведет себя по-разному для pow(3, 20) и pow(3, i), потому что он оценивает первый во время компиляции и последний во время выполнения.

Примечание

  1. Хорошие реализации pow возвращают ровно 3486784401 для pow(3, 20).К сожалению, плохие реализации могут возвращать неточные значения, такие как 3486784401.000000476837158203125 или 3486784400.999999523162841796875.
0 голосов
/ 19 ноября 2018

Результат pow(3,20) не может поместиться в int на вашей платформе (или моей в этом отношении).Из-за этого вы испытываете неожиданные результаты.

Переключение на больший целочисленный тип, такой как long long, сделает работу.

Более того, pow работает с числами с плавающей запятой, которые не представлены точно в памяти (посмотрите, чтовверх).Во время преобразования в целое число, это может вызвать определенные ошибки.Например, для printf("%fl\n", (pow(3,20))); я получаю 3486784401.000000l, который не является точным целочисленным значением.

...