PDA

View Full Version : Tại sao phép chia dư trong Pascal lại sai? VD: -7 mod 23



hcvtpt
14-11-2009, 17:45
Mình sử dụng hàm mod để thực hiện phép chia dư dãy số (có chứa cả số âm) thì được kết quả không đúng.
VD
begin
write(-7 mod 23);
readln;
end.

Nếu kết quả đúng theo như tính bằng Excel, thực tế thì kq phải là 16 nhưng chương trình trên lại in ra : -7.
Xin giúp đỡ.
Thanks!
PS:
Đây là kq test từ Google:
http://www.google.com.vn/#hl=vi&source=hp&q=-7+mod+23&btnG=T%C3%ACm+v%E1%BB%9Bi+Google&meta=&aq=f&oq=-7+mod+23&fp=1190927c2498a1c

[=========> Bổ sung bài viết <=========]

Mình đã kiểm tra bằng nhiều chương trình (không chỉ có Excel).
Bạn hãy thử vào và điền vào 1 ô: =MOD(-7,23)

Định lý về phép chia với dư
Giả sử cho hai số nguyên a và d, với d ≠ 0
Khi đó tồn tại duy nhất các số nguyên q và r sao cho a = qd + r và 0 ≤ r < | d |, trong đó | d | là giá trị tuyệt đối của d.
Các số nguyên trong định lý được gọi như sau

* q được gọi là thương khi chia a cho d. Đôi khi nó còn được gọi là thương hụt.
* r được gọi là dư khi chia a cho d
* d được gọi là số chia
* a được gọi là số bị chia

Phép toán tìm q và r được gọi là phép chia với dư.
Ví dụ

* Nếu a = 7 và d = 3, khi đó q = 2 và r = 1, vì 7 = (2)(3) + 1.
* Nếu a = 7 và d = −3, khi đó q = −2 và r = 1, vì 7 = (−2)(−3) + 1.
* Nếu a = −7 và d = 3, khi đó q = −3 và r = 2, vì −7 = (−3)(3) + 2.
* Nếu a = −7 và d = −3, khi đó q = 3 và r = 2, vì −7 = (−3)(−3) + 2.

Còn hàm trong Excel thì tính như thế này:
MOD(number,divisor)
Number is the number for which you want to find the remainder.
Divisor is the number by which you want to divide number.
Remarks

* If divisor is 0, MOD returns the #DIV/0! error value.
* The MOD function can be expressed in terms of the INT function:
MOD(n, d) = n - d*INT(n/d)

Trong đó: Hàm INT
INT(number)
Number is the real number you want to round down to an integer.
Example
The example may be easier to understand if you copy it to a blank worksheet.

jiSh@n
16-11-2009, 17:42
-7 chia 23 sẽ ra:
1) 0 lần, dư -7
2) -1 lần, dư 16
Cả 2 trường hợp này đều thỏa mãn a = qd + r, 0 ≤ r < |d|
Nhiều ngôn ngữ chọn 1, nhiều ngôn ngữ khác chọn 2. Bạn thấy cái nào hợp lý hơn ;)

Shellingfox
16-11-2009, 18:31
-7 chia 23 sẽ ra:
1) 0 lần, dư -7
2) -1 lần, dư 16
Cả 2 trường hợp này đều thỏa mãn a = qd + r, 0 ≤ r < |d|
Nhiều ngôn ngữ chọn 1, nhiều ngôn ngữ khác chọn 2. Bạn thấy cái nào hợp lý hơn ;)

Sai rồi Sơn ơi. Trường hợp 1 làm sao thoả biểu thức 0 ≤ r < |d| được. Không lẽ 0 ≤ -7 <= 23 à ?
Về mặt số học thì chỉ có trường hợp 2 là đúng thôi. -7 = -1x23 + 16; 0 ≤ 16 < 23

:D. Còn mấy ngôn ngữ thì chịu thua, xưa giờ không để ý cái điểm này mới chết :D.

jiSh@n
16-11-2009, 19:35
Sai rồi Sơn ơi. Trường hợp 1 làm sao thoả biểu thức 0 ≤ r < |d| được. Không lẽ 0 ≤ -7 <= 23 à ?
Về mặt số học thì chỉ có trường hợp 2 là đúng thôi. -7 = -1x23 + 16; 0 ≤ 16 < 23

:D. Còn mấy ngôn ngữ thì chịu thua, xưa giờ không để ý cái điểm này mới chết :D.

Điều kiện tổng quát là |r| < |d|, còn cái 0 ≤ r < |d| nó thuộc về định nghĩa Euclide do Raymond T. Boute đưa mà :emlaugh:

littlelee
16-11-2009, 20:55
Cái này thì dễ thôi, bạn thay vì tính =exel thì tính = mày tính bỏ túi thử xem nó ra bao nhiêu. mặc dù đứng là thế nhưng biết rồi thì mình chỉnh chương trình lại bình thường thôi, hỏi gì cho rắc rối.

hcvtpt
17-11-2009, 14:01
Cám ơn các bạn đã quan tâm.
Cuối cùng thì mình cũng tìm được nguyên nhân.
_____________________________________________
Nói kết quả của Pascal sai thực ra cũng không chính xác đâu.
Ta có: -7 = 16 + (-1).23
Nhưng cũng có: -7 = -7 + 0.23
Vấn đề ở đây là ta chấp nhận (hay quy ước) phần nguyên của phép chia đó là 0 hay -1 mà thôi.

Rất nhiều ngôn ngữ lập trình khác cũng quy ước rằng phép chia này có phần dư là -7, ví dụ: Turbo C, Turbo C++, MS Visual C++... Nhiều ứng dụng khác, ví dụ như bản thân phần mềm máy tính Calc đi kèm với Windows cũng chấp nhận phép chia này có phần dư là -7.

Vì thế, bạn cứ yên tâm sử dụng phép toán mod của Pascal mà không cần phải quá quan tâm chi tiết đó.

Trong trường hợp muốn thu được kết quả giống với Excel, bạn có thể viết như thế này:
phandu := sochia mod sobichia;
thuong := sochia div sobichia;
if phandu < 0 then
begin
phandu := phandu + sobichia;
thuong := thuong - 1;
end;

hang_vt
17-11-2009, 20:36
Cám ơn các bạn đã quan tâm.
Cuối cùng thì mình cũng tìm được nguyên nhân.
_____________________________________________
Nói kết quả của Pascal sai thực ra cũng không chính xác đâu.
Ta có: -7 = 16 + (-1).23
Nhưng cũng có: -7 = -7 + 0.23
Vấn đề ở đây là ta chấp nhận (hay quy ước) phần nguyên của phép chia đó là 0 hay -1 mà thôi.

Rất nhiều ngôn ngữ lập trình khác cũng quy ước rằng phép chia này có phần dư là -7, ví dụ: Turbo C, Turbo C++, MS Visual C++... Nhiều ứng dụng khác, ví dụ như bản thân phần mềm máy tính Calc đi kèm với Windows cũng chấp nhận phép chia này có phần dư là -7.

Vì thế, bạn cứ yên tâm sử dụng phép toán mod của Pascal mà không cần phải quá quan tâm chi tiết đó.

Trong trường hợp muốn thu được kết quả giống với Excel, bạn có thể viết như thế này:
phandu := sochia mod sobichia;
thuong := sochia div sobichia;
if phandu < 0 then
begin
phandu := phandu + sobichia;
thuong := thuong - 1;
end;

vấn đề là tại sao bạn quy ước là -1 mà k phải -2 ?

lehang_gb1
17-11-2009, 20:58
chắc là -1 là phạm vi gần nhất tức là -1*23 cho kết quả gần với -7 nhất

hang_vt
17-11-2009, 21:36
chắc là -1 là phạm vi gần nhất tức là -1*23 cho kết quả gần với -7 nhất

k hề có cơ sở
--------------------

Shellingfox
17-11-2009, 21:53
chắc là -1 là phạm vi gần nhất tức là -1*23 cho kết quả gần với -7 nhất

Cái đó đúng như jish@n nói đó là do cái biểu thức định nghĩa về số dư: |r| < |d| với r là số dư và d là số chia. Tuy nhiên trong số học hiện giờ thì hay sài kết quả là: 0 ≤ r < d để chỉ có 1 số dư mà thôi.

Như bài của bạn -7 = 16 + (-1)*23 (1) và -7 = -7 + 0*23 (2). Cả 2 trường hợp đều thỏa |16| < |23| (1) và |-7| < |23| (2).

Đối với số học mình học thì hiện tại chỉ lấy kết quả số dư là 16 vì số dư phải thỏa mãn: 0 ≤ r < d tức là 0 ≤ 16 < 23.

Do đó các ngôn ngữ lập trình tùy theo họ áp dụng biểu thức tính số dư kiểu nào mà có kết quả khác nhau. Chứ không phải là -1 có phạm vi gần nhất, nghe cái định nghĩa mơ hồ quá :-S

hang_vt
18-11-2009, 16:58
từ 0-> 23 có tới 24 nghiệm , tại sao lại chọn 16 ?

jiSh@n
18-11-2009, 21:08
từ 0-> 23 có tới 24 nghiệm , tại sao lại chọn 16 ?

Ở đâu ra 24 nghiệm :huh: Phép chia -7/23 = -0.304347826 khi lấy phần nguyên thì hoặc là truncate (0), hoặc là ceil (-1), hoặc là floor (0), chỉ có 2 kết quả là 0 hoặc -1, từ đó dẫn đến có 2 kết quả của phép mod.

technolt
20-11-2009, 04:37
Hình như các phép div, mod trên ý nghĩa toán học chỉ xét cho số dương :-?

jiSh@n
20-11-2009, 18:34
Hình như các phép div, mod trên ý nghĩa toán học chỉ xét cho số dương :-?

Miền giá trị là Z :innocent:

hang_vt
20-11-2009, 19:28
Hình như các phép div, mod trên ý nghĩa toán học chỉ xét cho số dương :-?

trên miền giá trị của biến integer

cm của mình :

CM -7 mod 23 = 16 TROG EXEL :
Lý thuyết đồng dư ( lớp 6,7 j` đó ):
- a,b chia cho m dư có cùng số dư => a,b đồng dư
- cho trước 1 số nguyên dương m , 2 số nguyên a,b đồng dư theo modulo m khi và chỉ khi a-b chia hết cho m

Trong vd của bạn :
a= -7
m = 23
a-b=n ( n là bội của 23 ) => 1 trong các nghiệm của b là 16
Ta có : -7, 16 đồng dư mà 16 mod 23 = 16 => -7 mod 23 = 16

CM -7 mod 23 = -7 TRONG PASCAL



-7 | 23
|----
-7 | 0



Tiểu học mình đã đc học cái này nà ( bài phép chia hết và phép chia có dư thì phải , lớp 2,3 j` đó ) :
số bị chia = số chia * thương + số dư
=> số dư = ( số bị chia ) - ( số chia * thương )
-7 = -7 - ( 23 * 0 ) ( luôn đúng )

vcuong27
27-11-2009, 19:47
trời đất có mỗi việc như vậy mà nói nhiều quá, chả ra sao cả .....
theo như mình thì thế nào chả dược.
quan trọng là khi viết chương trình chú ý cho nó ra kêt quả mình cần là dược thôi mà.