nhân mô-đun


7

Tôi đã đọc trang Nhân số mô-đun trên wikipedia ... và không thể hiểu thuật toán để tính toán .ab(modm)

uint64_t mul_mod(uint64_t a, uint64_t b, uint64_t m)
{
  long double x;
  uint64_t c;
  int64_t r;
  if (a >= m) a %= m;
  if (b >= m) b %= m;
  x = a;
  c = x * b / m;
  r = (int64_t)(a * b - c * m) % (int64_t)m;
  return r < 0 ? r + m : r;
}

Tôi hiểu điều đó:

ab(modm)((amodm)(bmodm))modm

Bước tôi không có được là c=x*b/mvà sau đó làm r = (int64_t)(a * b - c * m) % (int64_t)m;cái đó để làm gì?

Bài báo nói:

bằng cách sử dụng thủ thuật rằng, bằng phần cứng, phép nhân dấu phẩy động dẫn đến các bit quan trọng nhất của sản phẩm được giữ lại, trong khi phép nhân số nguyên dẫn đến các bit có trọng số thấp nhất được giữ

Tôi không thể thấy điều này có liên quan như thế nào !!!

Câu trả lời:


7

Đâ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 %= mabmodmx=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
xym=qxm+rxqxm=rxxmx=ab<m2x=x+eem
y=xm=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+emrx<me<mrx+e>mrx+e<0m2mrx+em0±1
xym=qxm+rxqxmrx+emm=rxrx+emm
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*bzmmz=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

zxmm=qzm+rzqzmqNmrz+rN+emm=rzqNmrz+rN+emm=rz+rNrz+rN+emm
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+em22m>NN=264m>2632m=N0e0m

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+dB0c<B0d<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ố.mabmmNm

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 doublecó 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 doublenà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 doublechỉ 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.


Câu trả lời nổi bật! Một trường hợp mà tôi vẫn gãi đầu: giả sử âm tính đến mức . Khi đó giá trị của sẽ là , và do đó trong phạm vi . Giả sử giá trị này là . Sau đó, cast tới (một loại đã ký) sẽ khiến nó bao quanh thành một số âm. Tại sao mã làm điều đúng trong trường hợp này? Cụ thể, trở thành sau khi chuyển đổi thành (nếu đó là ), và sau đó hoạt động -make-positive sẽ mang lại , thay vìerx+e<0a*b - c*mrx+mm..2m1263int64_trx+mrx+m264int64_t263%mrx264modmrx. (tt)
DW

Tôi chưa tìm thấy trường hợp thử nghiệm nào kích hoạt hành vi này. Đặc biệt, tôi không thể tìm thấy bất kỳ giá trị cho a, b, mnơi và nơi mà các giá trị là , tức là nơi và . Trường hợp này có thể xảy ra? Nếu nó có thể, tại sao mã này cho kết quả đúng trong tình huống đó? rx+e<0a*b - c*m263rx+e<0rx+m263
DW

Sau khi thử 1 tỷ giá trị ngẫu nhiên, tôi không thể tìm thấy bất kỳ trường hợp thử nghiệm nào thỏa mãn các điều kiện đó. Vậy có lẽ trường hợp này là không thể? Nhưng tại sao?
DW

Tôi đồng ý rằng tôi cũng không chắc chắn những gì xảy ra ở các cạnh. Trong trường hợp này, chúng ta có , và nên phạm vi của là đến . Vì điều này gây ra không có vấn đề trong các trường hợp , , . Tuy nhiên, chúng tôi không có vì vậy nếu chúng tôi có thể gặp sự cố, ví dụ: nếu cho . Tôi không biết nếu chúng ta sẽ0rz<m0rN<m|e|<mrz+rN+em12m<N1012m<NmN/2m263N=264có vấn đề mặc dù; Tôi cũng tin như thế. Mặt khác, nếu chế độ làm tròn được đặt thành làm tròn xuống, chúng ta sẽ có và tôi nghĩ rằng nó hoạt động hoàn toàn lên đến . e0m=N1
Derek Elkins rời SE

Cảm ơn đã chỉnh sửa và bình luận. Tuy nhiên, tôi vẫn không thấy cách giải quyết vụ việc mà tôi đang nói đến. Các trường hợp tôi đang lo lắng về là nơi là , và nơi (vì vậy mà các diễn viên đến sản lượng một tiêu cực con số). Nhận xét của bạn nói rằng không có vấn đề gì trong trường hợp , nhưng tôi không hiểu tại sao; đó chính xác là trường hợp tôi lo lắng. Tôi đã xem xét các chế độ làm tròn, nhưng từ những gì tôi có thể thấy, có vẻ như chế độ làm tròn mặc định là "làm tròn đến chẵn", không phải "làm tròn", do đó dường như không giải quyết được vấn đề. rz+rN+em1rz+rN+m263int64_t1
DW
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.