LINUX.ORG.RU

Переход чисел в отрицательные в C++


0

1

Есть задание - найти X чисел из последовательности Фибоначчи. По непонятной мне причине, после этого места:

701408733
1134903170
1836311903
-1323752223
512559680
-811192543
Числа положительные стали перемежаться числами отрицательными. Реализация очень проста:
a=0
b=1
цикл из
c=a+b
a=b+c
b=a+c
c=a+b
a=b+c
b=a+c
Подскажите, пожалуйста, в чем собака зарыта? Вроде даже негде...

★★

Последнее исправление: Valdor (всего исправлений: 1)

int это вроде от -2 миллиардов до +2 двух миллиардов. Когда переваливаешь за max_int, из числа вычиается 2^32 и оно превращается в отрицательное.

Kakadu
()
Ответ на: комментарий от Boy_from_Jungle

Тот, который я читал, говорит лишь о string, int, double, char. Во всяком случае, в первых нескольких главах.

Valdor ★★
() автор топика

Числа положительные стали перемежаться числами отрицательными.

переполнение. самый старший бит в знаковом инте, например, отвечает за знак.

aol ★★★★★
()
Ответ на: комментарий от gatsu

Взял long long. Отрицательности больше нет, но все равно немного чудит:

17704020980446223138
10627031650760492279
9884308557497163801
Как такое возможно?

Valdor ★★
() автор топика

Собака зарыта в переполнении int. Есть смысл взглянуть на библиотеку bignum, т.к. для подобной задачи и long long может не хватить.

beastie ★★★★★
()
Ответ на: комментарий от Valdor

но ощущение неприятное.

Ты хотел любые бесконечно большие числа int'ом или double'ом хранить? Напиши длинную арифметику для начала.

Redrum
()
Ответ на: комментарий от Boy_from_Jungle

Мне немного стыдно. Боюсь, сочтете быдлокодом. В любом случае:

#include <iostream>
using namespace std;

int main()
{
    int amount,amounts;
    unsigned long long a,b,c;
    cout << "Сколько чисел из последовательности Фибоначчи вы хотите получить?" << endl;
    cin >> amount;
    a = 0;
    amounts = 0;
    cout << a << "\n";
    amounts++;
    b = 1;
    cout << b << "\n";
    amounts++;

    while ( amounts != amount ) {
    c = a+b;
    cout << c << "\n";
    amounts++;
    a = c+b;
    cout << a << "\n";
    amounts++;
    b = a+c;
    cout << b << "\n";
    amounts++;
}
    return 0;
}
Еще не разобрался с проблемой, которая проявляется в том, что какого-то черта вычисление и вывод не останавливается, когда переменная amounts становится равна переменной amount (amount считывается в начале, а amounts равна 0 и увеличивается на один каждый раз. Но я разберусь.

Valdor ★★
() автор топика

Попробуй использовать библиотеку работающую с «длинными» числами (например gmp). Ну или реализуй длинную арифметику самостоятельно. Тем более реализовать нужно всего одну операцию:)

deadline
()

Используй какую-то библиотеку в которой есть тип числовой тип данных неограниченого размера. Например gmp. Или если только сложение, то напиши сам и храни каждое число в расширяющемся массиме из unsigned long например

vertexua ★★★★★
()
Ответ на: комментарий от Valdor

Ты в цикле инкрементируешь трижды amounts и иногда пролетаешь amount.

gatsu
()
Последнее исправление: gatsu (всего исправлений: 1)
Ответ на: комментарий от deadline

Так?

   do {
    c = a+b;
    cout << c << "\n";
    amounts++;
    a = c+b;
    cout << a << "\n";
    amounts++;
    b = a+c;
    cout << b << "\n";
    amounts++;
    }while (amounts != amount);
    return 0;
}
Если да - то ничто не изменилось.

Valdor ★★
() автор топика
Ответ на: комментарий от Valdor

Да, и условие у тебя неправильное. Если в цикле переменная amounts при инкременте «перескочит» значение amount то условие будет истинно. amounts > amount == amounts != amount. Поменяй условие на amounts < amount

deadline
()
Ответ на: комментарий от Valdor

Мне немного стыдно. Боюсь, сочтете быдлокодом.

Сочтем. Самый обычный быдлокод.

какого-то черта вычисление и вывод не останавливается, когда переменная amounts становится равна переменной amount

Hint: У тебя amounts на каждой итерации цикла while увеличивается на 3, а не на 1.

anonymous
()
Ответ на: комментарий от Valdor

Да какие муки?:) Возьми GMP(как выше уже два раза советовали), и напиши точно такую же программу. Туториалов по GMP полно в сети, в программе по-сути ничего не изменится кроме типа данных.

GMP - general multiprecision library

deadline
()
Ответ на: комментарий от Valdor

Некрасиво же. И вообще, у тебя три одинаковых вычисления идёт. Лучше переделать. Например через рекурсию, или через определители, или через золотое сечение(формула Бине)

deadline
()
Ответ на: комментарий от Valdor

ну или так

 typedef bigint unsigned long long;
 unsigned int amount = 0, current = 0;
 ...
 bigint Fprev = 0;
 bigint F = 1;
 bigint Fnext = 0;

do
{
    Fnext=Fprev+F;
    current++;
    Fprev=F;
    F=Fnext;
}while(current <= amount);

Ну или хотя бы так.

deadline
()

возьми ерланг. там такое из коробки.

nanoolinux ★★★★
()
Ответ на: комментарий от Valdor

Ну это понятно, но всё же лучше не писать бесконечные циклы без надобности. Не комильфо это. Руки сразу должны расти прямыми и шелковистыми:)

deadline
()
Ответ на: комментарий от Valdor

Я бы для такого юзал что-то типа python или java это раз.

Во-вторых продумать алгоритм, а потом писать.

Google-ch
()
Ответ на: комментарий от Valdor

Ничего в bignum сложного нет. Вот тебе первая тыща чисел:

/* gcc -o fib fib.c -lssl */

#include <openssl/bn.h>
#include <stdio.h>

int
main()
{
        BIGNUM r, a, b;
        int n;

        BN_init(&r);
        BN_init(&a);
        BN_init(&b);

        for (n = 0; n < 1000; n++) {
                switch (n) {
                case 0:
                        BN_zero(&r);
                        break;
                case 1:
                        BN_one(&r);
                        break;
                default:
                        BN_add(&r, &a, &b);
                        break;
                }

                BN_copy(&b, &a);
                BN_copy(&a, &r);

                puts(BN_bn2dec(&r)); /* тут надо бы free() */
        }

        return 0;
}

beastie ★★★★★
()
Ответ на: комментарий от beastie

а OpenSSL идёт в каждой поставке по-умолчанию.

если говорить про разработку - хедера надо ставить все-равно, если про перенос готовых бинарников - openssl вполне себе бывает разных версий

wota ★★
()

Чтобы в принципе избавиться от конечности типа данных, тебе потребуется что-то вроде Haskell :)
Смирись с наличием ограничения.

yura_ts ★★
()
Ответ на: комментарий от Valdor

У меня везде int. Предлагаешь взять double?

Тред не читал. Уже советовали unsigned?

#include <climits>
#include <iostream>
 
using namespace std;
 
int main() {
    int a = INT_MAX + 1;
    unsigned int b = (unsigned int)INT_MAX + 1;
    cout << "a: " << a << endl
         << "b: " << b << endl;
         
    return 0;
}

Результат: http://ideone.com/rdHMJR

взять double?

double - вещественный тип
int - целочисленный

KennyMinigun ★★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.