Почему я не могу хранить свои данные в длинном типе данных?
int power(int first,int second) {
int counter1 = 0;
long ret = 1;
while (counter1 != second){
ret *= first;
counter1 += 1;
}
return ret;
}
int main(int argc,char **argv) {
long one = atol(argv[1]);
long two = atol(argv[2]);
char word[30];
long finally;
printf("What is the operation? 'power','factorial' or 'recfactorial'\n");
scanf("%20s",word);
if (strcmp("power",word) == 0){
finally = power(one,two);
printf("%ld\n",finally);
return 0;
}
}
Эта функция предназначена для работы "мощности", как на калькуляторе, поэтому, если я пишу: ./a.out 5 3
, она даст мне 5 мощности 3 и распечатайте 125
Проблема в том, что числа, подобные цифрам: ./a.out 20 10
, 20 - мощность 10, я ожидаю увидеть результат: 1.024 x 10^13
, но вместо этого выводит 797966336
.
В чем причина текущего вывода, который я получаю?
Примечание. Я предполагаю, что это имеет какое-то отношение к типам данных atol()
и long
. Являются ли они недостаточно большими для хранения информации? Если нет, любая идея, как заставить его работать для больших чисел?
Ответы
Ответ 1
Конечно, ваши входы long
, но ваша функция power
принимает и возвращает int
! По-видимому, это 32-бит в вашей системе & hellip; поэтому в вашей системе 1,024 & times; 10 13 больше, чем int
может обрабатывать.
Убедитесь, что вы выбрали тип, который достаточно велик для ваших данных, и используйте его последовательно. Даже long
может быть недостаточно. проверьте свою систему!
Ответ 2
Прежде всего вам нужно изменить тип возвращаемого типа и ввести типы параметров power()
от int
до long
. В противном случае, в системе, где long
и int
имеют разный размер,
-
Входные аргументы могут быть усечены до int
, пока вы проходите long
.
-
Возвращаемое значение будет возвращено до int
перед возвратом, что может урезать фактическое значение.
После этого 1.024 × 10 13 (10240000000000) не может удерживаться символом int
или long
(если 32 бита). Вам нужно использовать тип данных с большей шириной, например long long
.
Ответ 3
один и два длинны.
long one = atol(argv[1]);
long two = atol(argv[2]);
Вы вызываете эту функцию с ними
int power(int first, int second);
Но ваша функция принимает int, здесь подразумевается неявное преобразование и возвращает int. Итак, ваши длинные int, которые вызывают поведение undefined (см. Комментарии).
Ответ 4
Быстрый ответ:
Значения вашей функции power
неявно преобразуются.
Измените параметры функции, чтобы ввести другой, а затем int
, который может содержать большие значения, одним возможным типом будет long
.
-
Входное значение получает тип, преобразованный и усеченный, чтобы соответствовать параметрам вашей функции.
-
Результат вычисления в теле функции будет снова преобразован в соответствие с типом возвращаемого значения, в вашем случае int
: не может обрабатывать размер значений.
Примечание 1: как отмечают более опытные участники, существует проблема с машиной, которая заключается в том, что ваш тип int
не обрабатывает обычный размер int
, который должен обрабатывать,
1. Чтобы сделать ответ полным
Ответ 5
Код смешивает int
, long
и надеется, что ответ превысит диапазон long
.
Ответ - это просто результат попыток положить 10 фунтов картофеля в 5-фунтовый мешок.
... идея, как заставить его работать для больших чисел.
- Используйте самое широкое целое число. Примеры:
uintmax_t
, unsigned long long
.
С C99 вперед обычно наибольшее представимое целое число будет UINTMAX_MAX
.
#include <stdint.h>
uintmax_t power_a(long first, long second) {
long counter1 = 0;
uintmax_t ret = 1;
while (counter1 != second){ // number of iterations could be in the billions
ret *= first;
counter1 += 1;
}
return ret;
}
Но давайте избежим проблемного поведения с отрицательными числами и повысим эффективность расчета от линейного к экспоненциальному.
// return x raised to the y power
uintmax_t pow_jululu(unsigned long x, unsigned long y) {
uintmax_t z = 1;
uintmax_t base = x;
while (y) { // max number of iterations would bit width: e.g. 64
if (y & 1) {
z *= base;
}
y >>= 1;
base *= base;
}
return z;
}
int main(int argc,char **argv) {
assert(argc >= 3);
unsigned long one = strtoul(argv[1], 0, 10);
unsigned long two = strtoul(argv[2], 0, 10);
uintmax_t finally = pow_jululu(one,two);
printf("%ju\n",finally);
return 0;
}
Этот подход также имеет пределы. 1) z *= base
может математически переполняться для вызовов типа pow_jululu(2, 1000)
. 2) base*base
может математически переполняться в необычной ситуации, когда unsigned long
больше половины ширины uintmax_t
. 3) некоторые другие нюансы тоже.
- Курорт для других типов, например:
long double
, Арифметика с произвольной точностью. Это, вероятно, выходит за рамки этой простой задачи.
Ответ 6
Вы можете использовать длинный длинный 8 байтов в длину вместо 4-байтовой длины long и int.
long long предоставит вам значения от -9,223,372,036,854,775,808 до 9,223,372,036,854,775,807. Это, я думаю, должно охватывать все значения, с которыми вы можете столкнуться только сейчас.