Đây là một mô tả toán học nhỏ gọn hơn về những gì đang diễn ra. Đặt và là đầu vào, đã giảm modulo , vì vậy và . (Code-khôn ngoan, điều này có nghĩa là sau dòng.) Chúng tôi muốn tính , nghĩa là đặt , chúng tôi muốn tìm sao cho cho một số .abma<mb<mb %= m
abmodmx=abrxx=qxm+rxqx
Trường hợp không tràn
Trong trường hợp không tràn, chúng ta chỉ cần tính toán mô đun và được thực hiện với nó. Thay vào đó, mã tính toán:
Bây giờ . Tôi đã bỏ qua một mối quan tâm ở đây mặc dù. Có thể là không phù hợp với vị trí của biến dấu phẩy động của chúng ta. Tuy nhiên, miễn là phù hợp, điều này sẽ không thành vấn đề vì . Chúng tôi sẽ kết thúc với trong đó là một số lỗi làm tròn có cường độ nhỏ hơn . Chúng tôi tiến hành như trước:
y=⌊xm⌋=⌊qx+rxm⌋=qx+⌊rxm⌋=qx
x−ym=qxm+rx−qxm=rxxmx=ab<m2x′=x+eemy=⌊x′m⌋=⌊qx+rx+em⌋=qx+⌊rx+em⌋
Trong trường hợp này, chúng tôi không thể loại bỏ bởi vì, trong khi và , đó có thể là trường hợp hoặc , mặc dù chắc chắn nó sẽ nằm trong khoảng từ đến , vì vậy là hoặc . Bây giờ
⌊rx+em⌋rx<me<mrx+e>mrx+e<0−m2m⌊rx+em⌋0±1x−ym=qxm+rx−qxm−⌊rx+em⌋m=rx−⌊rx+em⌋m
Việc thực hiện thao tác mô đun bây giờ sẽ thoát khỏi điều khoản phụ đó, tuy nhiên, do
quy ước C chọn ,
(-1)%m = -1
. Để có được một quy ước trong đó chúng ta luôn trả về một số dương, chúng ta có thể thêm vào kết quả nếu âm.
m
Trường hợp tràn
Giả sử rằng chúng ta đang thực hiện mod số học số nguyên , ví dụ và giả sử có nghĩa là . Bây giờ nhân sẽ được bọc. Chúng ta sẽ viết cho một số nguyên . Điều đó có nghĩa là tính toán sẽ cho số . Việc tính toán dấu phẩy động như trước khi giả định, một lần nữa, phù hợp với lớp phủ (có thể yêu cầu độ chính xác mở rộng 80 bit cho lớn hơn ). Đối với mô đun, xác định và đểN264ab>Nm2>N>mx=ab=z+kNk<ma*b
zmmz=qzm+rzkN=qNm+rNx=qzm+qNm+rz+rN. Như trước khi lưu dưới dạng biến dấu phẩy động có thể tạo ra một số lỗi làm tròn nên lại có . Nếu chúng ta thực hiện phép tính tương tự như trước thì có vẻ như:
Tôi đã kéo một con thỏ ra khỏi chiếc mũ ở đây. Ở đây, chúng tôi đang thực hiện bổ sung mod và mod nên . Như trước đây, chúng tôi mod bằng để có đượcx|e|<mx′=x+e
z−⌊x′m⌋m=qzm+rz−qzm−qNm−⌊rz+rN+em⌋m=rz−qNm−⌊rz+rN+em⌋m=rz+rN−⌊rz+rN+em⌋m
NN qNm+rN=kN=0qNm=−rNmrz+rN=xmodm , và, như trước đây, quy ước C có thể dẫn đến điều này là tiêu cực sẽ cần phải sửa.
Có một vấn đề tiềm năng còn lại. có thể là . Điều này không gây ra vấn đề gì trừ khi trong trường hợp bạn nhận được câu trả lời sai. Với điều này có nghĩa là . (Là một sang một bên, nếu nó gây ra không có vấn đề vì chúng ta sẽ kết thúc với .) Nếu chúng ta cấu hình phần cứng dấu chấm động để giảm vòng để , trường hợp này sẽ không đi lên. (Mặc dù đừng quên hạn chế của tôi rằng bọ ngựa có thể giữ !).⌊rz+rN+em⌋22m>NN=264m>2632m=N0e≤0m
Kết nối này với hầu hết các bit quan trọng nhất
Để giải quyết cụ thể phần mà bạn đã trích dẫn, hãy xem xét một số nguyên, , lớn hơn 2 mà chúng ta sẽ nghĩ là cơ sở, như trong "cơ sở ". Trong trường hợp thông thường , số được biểu diễn là . Trong một biểu diễn dấu phẩy động, chúng tôi sẽ viết điều này là . Bây giờ, giả sử chúng tôi muốn nhân hai số có một chữ số cơ bản (dương) , kết quả sẽ yêu cầu tối đa hai chữ số, giả sử trong đó (theo yêu cầu của biểu diễn [tiêu chuẩn] cơ sở ) và . Nếu chúng tôi bị hạn chế chỉ có thể lưu trữ một cơ sởB10B=102121=2B+12.1×B1BcB+dB0≤c<B0≤d<BB chữ số của kết quả, có hai lựa chọn rõ ràng, hoặc hoặc .cd
Chọn tương đương với mod làm việc là , đây là điều xảy ra với số học số nguyên. (Ngẫu nhiên, ở cấp độ lắp ráp, phép nhân số nguyên thường không tạo ra cả hai chữ số này.)dBcB+d=dmodB
Mặt khác, số học dấu phẩy động tương ứng với việc chọn , nhưng bù lại bằng cách tăng số mũ. Trong thực tế, chúng tôi biểu thị kết quả là nhưng vì chúng tôi chỉ có thể lưu trữ một chữ số cơ sở , nên điều này trở thành chỉ . (Trong thực tế, chúng tôi sẽ coi các số là số có nhiều chữ số trong một cơ sở nhỏ (tức là 2), thay vì số 1- hoặc 2 chữ số trong một cơ sở lớn. Điều này cho phép chúng tôi lưu một số chữ số cao hơn của nếu họ không cần lưu trữ , nhưng trong trường hợp xấu nhất thì tất cả bị mất. Không cócc.d×B1Bc×B1dcdcbị mất cho đến khi chúng tôi bắt đầu chạy ra khỏi phòng theo cấp số nhân. Đối với mã ở trên, đây không phải là một vấn đề.)
Chừng nào có thể được biểu diễn một cách trung thực trong các định dạng dấu chấm động, khái niệm có thể được xem như là giải nén mà chữ số trên trong cơ sở- . Bạn có thể xem mã và toán trên như hưởng lẫn nhau giữa cơ sở- và cơ sở- đại diện của một số.m⌊abm⌋mNm
Thực tiễn
Dựa trên mục 5.2.4.2.2 của dự thảo này , tiêu chuẩn C11 dường như chỉ yêu cầu long double
có một lớp phủ dài khoảng 33 bit. (Cụ thể, dường như chỉ xác định số chữ số thập phân tối thiểu có thể được biểu diễn một cách trung thực.) Trong thực tế, hầu hết các trình biên dịch C khi nhắm mục tiêu CPU mục đích chung và CPU gia đình x86, sẽ sử dụng các loại IEEE754. Trong trường hợp double
này sẽ có một mantissa 53 bit. CPU gia đình x86 hỗ trợ định dạng 80 bit với mantissa với 64 bit hiệu quả và một số nhưng không phải tất cả các trình biên dịch sẽ long double
chỉ ra rằng khi nhắm mục tiêu x86. Phạm vi hiệu lực của mã phụ thuộc vào các chi tiết triển khai này.
a*b - c*m
int64_t
int64_t
%m