01/10/2018, 09:26

Phép tính đơn giản nhưng kết quả sai?

Xin chào anh/chị và các bạn , mình đang gặp LỖI với phép tính sau :

float x1,x2,y1,y2;
x1=106.036;
y1=20.56213;
x2= 106.03519;
y2=20.562710;
double pre = x1y2-y1x2;

Kết quả khi in ra : pre=0.078125.
Trong khi kết quả chính xác phải là: pre=0.07815620.
Đây là nguyên nhân chính khiến các phép tính của mình bị sai lệch rất lớn phía sau.
Mong anh chị và các bạn giúp mình tìm ra nguyên nhân và cách khắc phục.
(mình lập trình trên phần mềm processing, với kiểu double cỡ 8 byte)

Nick Chung viết 11:38 ngày 01/10/2018

Đây là kết quả tính trên google, mình rất bí trong trường hợp này !

Khoa NTA viết 11:29 ngày 01/10/2018

Mình không hiểu nữa, có lẽ như kiểu float không biểu diễn được đầy đủ. Nếu thay kiểu x1, x2,… bằng double thì kết quả cho ra như bạn mong đợi.
http://cpp.sh/8cku

Nick Chung viết 11:32 ngày 01/10/2018

Mình đã thử thay x1,x2,x3,x4 là kiểu double nhưng kết quả vẫn không khá hơn ?!
pre thậm chí bằng: 0.078269

Đức Anh Lê viết 11:40 ngày 01/10/2018

bạn thử long double đi

Đức Anh Lê viết 11:38 ngày 01/10/2018

ko thì bạn thử in biểu thức kia ra thay vì gán vào biến xem sao

Nick Chung viết 11:41 ngày 01/10/2018

mình đã thử rút ngắn để nó “có vẻ” vừa với float nhưng kết quả vẫn lệch :x1 = 106.036; y1 = 20.56213; x2 = 106.0351; y2 = 20.56271;

Đức Anh Lê viết 11:36 ngày 01/10/2018

bạn thử in từng cái ra xem bên trong nó bằng bao nhiêu sau đó in cả biểu thức ra xem sao

Nick Chung viết 11:32 ngày 01/10/2018

Với cách in trực tiếp : Kết quả vẫn là pre=0.07826.
Với Long Double : procesing không có kiểu dữ liệu này. Hơn nữa mình chỉ muốn dừng lại ở Float hoặc Double để phù hợp với vi điều khiển !

Đức Anh Lê viết 11:36 ngày 01/10/2018

dung %lf để in long double thử đi nếu vẫn sai thì tính cách khác

Trần Hoàn viết 11:31 ngày 01/10/2018

Kiểu float chỉ cho lưu được 6 chữ số sau dấu phẩy.
Kiểu double thì được thừa đến 7

Nick Chung viết 11:34 ngày 01/10/2018

Mình tiếp tục rút ngắn nhưng kết quả lệch là “quá lớn”

float x1,x2,y1,y2;
x1 = 106.036;
y1 = 20.5621;
x2 = 106.0351;
y2 = 20.5627;
double pre = x1y2-y1x2;

với X,Y double: pre=0.0821275
với XY float :pre= 0.0820312
Kết quả chung cuộc trên google cho phép tính trên :
pre=0.08212748999.
Như vậy : kể cả khi xóa các số phía sau thì Float vẫn không phù hợp ?
(Mình nghĩ việc xóa chỉ là cho các số sau dấu phảy =0 )
Hơn nữa mình sẽ không thể tiếp tục xóa vì các giá trị kinh độ-vĩ độ đều phải có ít nhất 6 số sau dấu phảy, các kết quả mô phỏng phía trên khiến mình bị lệch hàng trăm km, và không thể sử dụng trên các dòng vi điều khiển AVR.

gioi viết 11:27 ngày 01/10/2018

Bạn có đọc trong đây chưa:

https://processing.org/reference/float.html

“Floats are not precise, so adding small values (such as 0.0001) may not always increment precisely due to rounding errors. If you want to increment a value in small intervals, use an int, and divide by a float value before using it. (See the second example above.)”

Bạn thử làm như cách họ gợi ý xem sao

Nick Chung viết 11:40 ngày 01/10/2018

Mình đang đọc thử, cảm ơn bạn.

Nguyễn Duy Hùng viết 11:29 ngày 01/10/2018

Dùng decimal thử xem.

Nick Chung viết 11:40 ngày 01/10/2018

Bạn gợi ý cho mình chứ , “decimal” mình chưa từng nghe qua (mình ở bên Tự Động Hóa)

gioi viết 11:42 ngày 01/10/2018

Vẫn chưa được à.
Nếu kẹt quá thì cheat đi.
Nhân cho 1000 trước:
x1 *=1000;
y1 *=1000;

sau khi tính pre thì chia lại cho 1.000.000
Xem kết quả thử coi có được không.

viết 11:31 ngày 01/10/2018

float x1,x2,y1,y2; x1=106.036; y1=20.56213; x2= 106.03519; y2=20.562710;double pre = x1y2-y1x2;

#include <iostream>

int main()
{
    double x1,x2,y1,y2;
    x1=106.036;
    y1=20.56213;
    x2= 106.03519;
    y2=20.562710;
    double pre = x1*y2-y1*x2;
    std::cout << pre << "\n";
}

kết quả là 0.0781562

làm gì mà “pre thậm chí bằng: 0.078269”?? Có chuyển về double chưa vậy??

Find&replace, tìm float thay bằng double hết là xong. Còn bên trong thư viện tính toán mà nó dùng float thì tìm xem thư viện nó cho xài double ko, chắc chắn phải có.

Nick Chung viết 11:29 ngày 01/10/2018

Bạn “gioi” Mình thử rùi, mình cho XY nhân với 1000000 để đảm lấy 6 số phía sau, lưu với long, rồi chia lại và ép kiểu nhưng kết quả vẫn giống hệt với cách dùng float, có lẽ là do float không chứa nổi . Kiểu này phải tìm phương pháp thủ công để tính số trên hệ nhị phân.

Nick Chung viết 11:29 ngày 01/10/2018

Bạn “tntxtnt” : Mình nhân trên procesing của mình nó vậy mà:

viết 11:29 ngày 01/10/2018

vậy cái này do lỗi phần mềm Processing gì rồi, chắc bên trong nó tính bằng float nên vậy. Đốt phần mềm đó đi @_@

vô cái forum hay github hay gửi email cho Processing chửi họ sao phép tính đơn giản xài double lại cho kết quả tầm bây.

Bài liên quan
0