uint64_t неправильно достиг 18 446 744 071 590 568 320

Всякий раз, когда я ввожу возраст 65 лет или меньше, я получаю число где-то меньше 2 100 000. Однако, когда я ввожу возраст 68 лет или выше, результат сразу же становится равным 18 446 744 071 590 568 320, что является максимальным значением для uint64_t. Я понятия не имею, почему такой скачок в результатах. До 2 100 000 работает нормально.

// How many seconds have I lived?
#include <stdio.h>
#include <string>
#include <cstdint>
using namespace std;
string addCommas(uint64_t answer);
int main ()
{
    int seconds = 60, minutes = 60, hours = 24, days = 365;
    int years; uint64_t secondsLived, secondsAwake;
    printf("How many years have you lived? ");
    scanf("%d",&years);
    secondsLived = seconds*minutes*hours*days*years;
    secondsAwake = (float)secondsLived*0.666;

    printf("\nYou have existed for %s seconds\n",addCommas(secondsLived).c_str());
    printf("You have been awake for %s seconds\n",addCommas(secondsAwake).c_str());
}
string addCommas(uint64_t answer){
    string num = to_string(answer);
    int insertplace = (int)num.length() - 3;
    while (insertplace > 0) {
        num.insert(insertplace, ",");
        insertplace-=3;
    }
    return num;
}

Вот пара выводов:

How many years have you lived? 67

You have existed for 2,112,912,000 seconds
You have been awake for 1,407,199,392 seconds


How many years have you lived? 69

You have existed for 18,446,744,071,590,568,320 seconds
You have been awake for 12,285,531,553,090,562,048 seconds

person carljalal    schedule 12.06.2014    source источник
comment
Почему printf и scanf, а что не так с cin и cout?   -  person yizzlez    schedule 13.06.2014
comment
@awesomeyi: Не то чтобы это применимо к этому случаю, но cin и cout действительно, действительно, значительно и заметно медленнее, чем scanf и printf   -  person Armen Tsirunyan    schedule 13.06.2014
comment
18 446 744 071 590 568 320 не является максимальным значением uint64_t; это 18 446 744 073 709 551 615. (Конечный 0 должен был быть подсказкой.) В шестнадцатеричном формате это 0xffffffff81b2e180 против 0xffffffffffffffff.   -  person Keith Thompson    schedule 13.06.2014


Ответы (3)


В этой строке:

secondsLived = seconds*minutes*hours*days*years;

Вы умножаете число int вместе, а затем присваиваете результат uint_64. Вычисление на ints переполняется.

Приведите по крайней мере одно из значений к uint_64 перед их перемножением, чтобы вычисление выполнялось для uint_64 значений:

secondsLived = (uint_64)seconds*minutes*hours*days*years;
person Jesper    schedule 12.06.2014

secondsLived = seconds*minutes*hours*days*years;

Тот факт, что вы присваиваете результат uint64_t, не влияет на то, как он вычисляется.

person David Schwartz    schedule 12.06.2014

Поскольку seconds, minutes, hours, days и years являются целыми числами со знаком, все вычисления выполняются в целых числах со знаком. Когда вы вводите большое количество лет, оно переполняется int. Когда переполненный результат преобразуется в 64-битное целое число без знака, вы получаете очень большое число из-за того, как отрицательные числа представлены в системе дополнения до двух.

Объявление любой из юнит-переменных (скажем, years) как uint64_t решит эту проблему:

int seconds = 60, minutes = 60, hours = 24, days = 365;
uint64_t years, secondsLived, secondsAwake;
person Sergey Kalinichenko    schedule 12.06.2014