30/09/2018, 18:43

String đột nhiên thay đổi giá trị

Em đang tìm số fibo nhỏ nhất >= tmp, với F, tmp đều là std::string
Hàm lessThan trả về true nếu F[i] < tmp
Hàm add() để cộng 2 string lại (tất nhiên là string chứa các chữ số)

            while(lessThan(F[i], tmp))
            {
                ++i;
                F[i] = add(F[i - 1], F[i - 2]);
                //std::cout << F[i] << '
' << tmp << '
';
            }

Khi em để tmp là 1 số lớn (1000 chữ số 9) thì em tính F. Mọi chuyện vẫn ổn cho tới bước lặp cuối cùng, F[i] tính ra được là 24314… (ví dụ vậy), còn tmp đang mang giá trị 1000 chữ số 9 thì bỗng nhiên đổi thành 24314…

Mọi người cho em hỏi là tại sao lại vậy ?

Phạm Đại Nghĩa viết 20:45 ngày 30/09/2018

Bởi vì giá trị của kiểu Int nó ko lớn đến 1000 chữ số 9 đâu bạn.

nhatlonggunz viết 20:44 ngày 30/09/2018

Dạ, em để biến tmp là std::string anh ơi

Phạm Đại Nghĩa viết 20:57 ngày 30/09/2018

Nhưng bạn phải xem cả hàm lessThan kia nữa. Biết đâu trong đó bạn convert tmp thành int. Vì nếu không thì làm sao so sánh less than được giữa 1 integer và 1 string với nhau.

Phạm Đại Nghĩa viết 20:53 ngày 30/09/2018

Bạn thử xem cái số lúc bạn bị lỗi có phải số này không: 2147483648. Đây là số lớn nhất của kiểu int.

nhatlonggunz viết 20:44 ngày 30/09/2018

Hic, ở đây, chỉ có biến i là int
Còn lại, F, tmp, là std::string hết
Em có nói rõ rồi mà.

Phạm Đại Nghĩa viết 20:59 ngày 30/09/2018

Vậy i làm sao chạy qua giới hạn của kiểu Int được bạn?

nhatlonggunz viết 20:57 ngày 30/09/2018

Số Fibo có 1000 chữ số là cỡ số thứ 4900, nghĩa là i chỉ chạy tới 4900 thôi ^^

Phạm Đại Nghĩa viết 20:51 ngày 30/09/2018
  1. A ko hiểu vì sao e lại dùng while(lessThan(abc < xyz)) trong khi xyz là 1 số cực lớn mà ko số nào lớn hơn được. Vì sao ko thay bằng while(true)?
  2. Để so sánh lessThan thì chắc chắn ko thể so sánh 2 string được mà bắt buộc phải convert nó từ string ra 1 loại number nào đó. Khả năng rất cao trong TH này là kiểu Int. E cần check lại đi.
  3. Trong vòng lặp của e không có điều kiện break do số tmp là số cực lớn mà F[i] ko thể lớn hơn được thì i chạy quá giới hạn Int là chuyện bình thường mà.
nhatlonggunz viết 20:51 ngày 30/09/2018

Dạ, nói ngắn gọn thì đây là xử lý số lớn nha anh ^^
Anh có thể google ^^

Phạm Đại Nghĩa viết 20:48 ngày 30/09/2018

Haha, vậy chúc e tìm lỗi thành công.

Minh Hoàng viết 20:43 ngày 30/09/2018

Em cần chắc chắn các hàm này làm đúng nhiệm vụ của nó. Do ko xem đc hàm lessthan và hàm cộng nên anh ko kiểm tra đc, em post lên đc ko?
Hàm lessthan có truyền tham chiếu tmp ko? Vì chỉ có hàm này mới thay đổi đc tmp nên kiểm tra lại xem. Còn mà nó là truyền giá trị mà tmp vẫn bị thay đổi thì bí ẩn quá

nhatlonggunz viết 21:00 ngày 30/09/2018

Đây là toàn bộ chương trình của e.
Đề: nhập Q là số truy vấn. Với mỗi truy vấn, nhập một số tối đa 1000 chữ số và kiểm tra xem đó có phải là số Fibo hay không.

#include <iostream>
#include <string>
#define maxN 5000
std::string F[maxN], tmp, gg;
int m;

int toNum(char c) { return c - '0'; }
char toChar(int n) { return n + '0'; }
std::string add(std::string a, std::string b)
{
    int carry = 0, tmp;
    while(a.length() < b.length()) a = '0' + a;
    while(a.length() > b.length()) b = '0' + b;

    for(int i = a.length() - 1; i >= 0; i--)
    {
        tmp = toNum(a[i]) + toNum(b[i]) + carry;
        a[i] = toChar(tmp % 10);
        carry = tmp / 10;
    }

    if(carry > 0) a = toChar(carry) + a;
    return a;
}
bool lessThan(std::string a, std::string b)
{
    if(a.length() < b.length()) return true;
    return a < b;
}

int main()
{
    F[1] = "1"; F[2] = "1";
    std::cin >> m;
    int i = 2;

    while(m--)
    {
        std::cin >> tmp;

        if(lessThan(F[i], tmp))
        {

            while(lessThan(F[i], tmp))
            {
                ++i;
                F[i] = add(F[i - 1], F[i - 2]);
                //std::cout << F[i] << '\n' << tmp << '\n';
            }
        }
        else
        {
            for(int j = 2; j <= i; j++)
                if(F[j] == tmp)
                    { i = j; break; }
        }
        if(F[i] == tmp)
            std::cout << "YES\n";
        else
            std::cout << "NO\n";
    }

    return 0;
}

Gió viết 20:48 ngày 30/09/2018

Em đưa toàn bộ code lên xem

Gió viết 20:48 ngày 30/09/2018

while(carry){ a+=toChar(carry%10); carry/=10);}

không nên dùng phép cộng của string nhiều như thế. Tốt nhất là push_back vào sau rồi đảo ngược lại

nhatlonggunz viết 20:54 ngày 30/09/2018

Nhưng em vẫn không hiểu sao, các lần lặp trước đều đúng hết, nhưng chỉ tới bước lặp cuối cùng thì tmp lại chuyển luôn :’(

@ltd Nó liên quan gì đến vùng nhớ này nọ không anh

nhatlonggunz viết 20:49 ngày 30/09/2018

Đây là giá trị debug
Cái số 999… là giá trị của tmp, số rối rắm kia là số fib.
Và thấy rằng, đến bước lặp cuối, từ 999…, tmp đã chuyển sang giống fib[i] hoàn toàn :’(

Pham Van Hai viết 20:59 ngày 30/09/2018

Mình copy, thử build và chạy thử chương trình của bạn thì không thấy lỗi gì:

D:\exam>a
2
1
YES
34
YES

Mình dùng g++:

D:\exam>g++ --version
g++ (x86_64-posix-sjlj, built by strawberryperl.com project) 4.9.2
Copyright (C) 2014 Free Software Foundation, Inc.
Minh Hoàng viết 20:52 ngày 30/09/2018

Thay hàm lessthan. Hàm cũ chạy mãi mà nó không chịu dừng

bool lessThan(std::string a, std::string b)
{
	
	if (a.length() < b.length()) return true;
	if (a.length() == b.length()) return (a<b);
	return false;
}

Anh thử với input 1040 số 9.

nhatlonggunz viết 20:47 ngày 30/09/2018

Cám ơn mấy anh em sửa theo anh @rok_Hoang thì chạy được rồi.
Mà nếu được, mấy anh có thể giải thích tại sao cái chương trình ban đầu biến tmp bị đổi giá trị không ?

Gió viết 20:54 ngày 30/09/2018

{i=j; break;}??? Cái này giảm i để làm gì

if(F[j]==tmp)

tốt nhất là sinh hết 1000 số fibinacci rồi tìm kiếm nhị phân không hay hơn là cứ tìm tuần tự thế này. Nếu q=1000 và n đều là 1000 thì tìm theo cách này k chạy nổi đâu

Bài liên quan
0