Path: blob/main/Modules/_decimal/libmpdec/literature/fnt.py
12 views
#1# Copyright (c) 2008-2020 Stefan Krah. All rights reserved.2#3# Redistribution and use in source and binary forms, with or without4# modification, are permitted provided that the following conditions5# are met:6#7# 1. Redistributions of source code must retain the above copyright8# notice, this list of conditions and the following disclaimer.9#10# 2. Redistributions in binary form must reproduce the above copyright11# notice, this list of conditions and the following disclaimer in the12# documentation and/or other materials provided with the distribution.13#14# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND15# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE16# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE17# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE18# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL19# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS20# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)21# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT22# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY23# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF24# SUCH DAMAGE.25#262728######################################################################29# This file lists and checks some of the constants and limits used #30# in libmpdec's Number Theoretic Transform. At the end of the file #31# there is an example function for the plain DFT transform. #32######################################################################333435#36# Number theoretic transforms are done in subfields of F(p). P[i]37# are the primes, D[i] = P[i] - 1 are highly composite and w[i]38# are the respective primitive roots of F(p).39#40# The strategy is to convolute two coefficients modulo all three41# primes, then use the Chinese Remainder Theorem on the three42# result arrays to recover the result in the usual base RADIX43# form.44#4546# ======================================================================47# Primitive roots48# ======================================================================4950#51# Verify primitive roots:52#53# For a prime field, r is a primitive root if and only if for all prime54# factors f of p-1, r**((p-1)/f) =/= 1 (mod p).55#56def prod(F, E):57"""Check that the factorization of P-1 is correct. F is the list of58factors of P-1, E lists the number of occurrences of each factor."""59x = 160for y, z in zip(F, E):61x *= y**z62return x6364def is_primitive_root(r, p, factors, exponents):65"""Check if r is a primitive root of F(p)."""66if p != prod(factors, exponents) + 1:67return False68for f in factors:69q, control = divmod(p-1, f)70if control != 0:71return False72if pow(r, q, p) == 1:73return False74return True757677# =================================================================78# Constants and limits for the 64-bit version79# =================================================================8081RADIX = 10**198283# Primes P1, P2 and P3:84P = [2**64-2**32+1, 2**64-2**34+1, 2**64-2**40+1]8586# P-1, highly composite. The transform length d is variable and87# must divide D = P-1. Since all D are divisible by 3 * 2**32,88# transform lengths can be 2**n or 3 * 2**n (where n <= 32).89D = [2**32 * 3 * (5 * 17 * 257 * 65537),902**34 * 3**2 * (7 * 11 * 31 * 151 * 331),912**40 * 3**2 * (5 * 7 * 13 * 17 * 241)]9293# Prime factors of P-1 and their exponents:94F = [(2,3,5,17,257,65537), (2,3,7,11,31,151,331), (2,3,5,7,13,17,241)]95E = [(32,1,1,1,1,1), (34,2,1,1,1,1,1), (40,2,1,1,1,1,1)]9697# Maximum transform length for 2**n. Above that only 3 * 2**3198# or 3 * 2**32 are possible.99MPD_MAXTRANSFORM_2N = 2**32100101102# Limits in the terminology of Pollard's paper:103m2 = (MPD_MAXTRANSFORM_2N * 3) // 2 # Maximum length of the smaller array.104M1 = M2 = RADIX-1 # Maximum value per single word.105L = m2 * M1 * M2106P[0] * P[1] * P[2] > 2 * L107108109# Primitive roots of F(P1), F(P2) and F(P3):110w = [7, 10, 19]111112# The primitive roots are correct:113for i in range(3):114if not is_primitive_root(w[i], P[i], F[i], E[i]):115print("FAIL")116117118# =================================================================119# Constants and limits for the 32-bit version120# =================================================================121122RADIX = 10**9123124# Primes P1, P2 and P3:125P = [2113929217, 2013265921, 1811939329]126127# P-1, highly composite. All D = P-1 are divisible by 3 * 2**25,128# allowing for transform lengths up to 3 * 2**25 words.129D = [2**25 * 3**2 * 7,1302**27 * 3 * 5,1312**26 * 3**3]132133# Prime factors of P-1 and their exponents:134F = [(2,3,7), (2,3,5), (2,3)]135E = [(25,2,1), (27,1,1), (26,3)]136137# Maximum transform length for 2**n. Above that only 3 * 2**24 or138# 3 * 2**25 are possible.139MPD_MAXTRANSFORM_2N = 2**25140141142# Limits in the terminology of Pollard's paper:143m2 = (MPD_MAXTRANSFORM_2N * 3) // 2 # Maximum length of the smaller array.144M1 = M2 = RADIX-1 # Maximum value per single word.145L = m2 * M1 * M2146P[0] * P[1] * P[2] > 2 * L147148149# Primitive roots of F(P1), F(P2) and F(P3):150w = [5, 31, 13]151152# The primitive roots are correct:153for i in range(3):154if not is_primitive_root(w[i], P[i], F[i], E[i]):155print("FAIL")156157158# ======================================================================159# Example transform using a single prime160# ======================================================================161162def ntt(lst, dir):163"""Perform a transform on the elements of lst. len(lst) must164be 2**n or 3 * 2**n, where n <= 25. This is the slow DFT."""165p = 2113929217 # prime166d = len(lst) # transform length167d_prime = pow(d, (p-2), p) # inverse of d168xi = (p-1)//d169w = 5 # primitive root of F(p)170r = pow(w, xi, p) # primitive root of the subfield171r_prime = pow(w, (p-1-xi), p) # inverse of r172if dir == 1: # forward transform173a = lst # input array174A = [0] * d # transformed values175for i in range(d):176s = 0177for j in range(d):178s += a[j] * pow(r, i*j, p)179A[i] = s % p180return A181elif dir == -1: # backward transform182A = lst # input array183a = [0] * d # transformed values184for j in range(d):185s = 0186for i in range(d):187s += A[i] * pow(r_prime, i*j, p)188a[j] = (d_prime * s) % p189return a190191def ntt_convolute(a, b):192"""convolute arrays a and b."""193assert(len(a) == len(b))194x = ntt(a, 1)195y = ntt(b, 1)196for i in range(len(a)):197y[i] = y[i] * x[i]198r = ntt(y, -1)199return r200201202# Example: Two arrays representing 21 and 81 in little-endian:203a = [1, 2, 0, 0]204b = [1, 8, 0, 0]205206assert(ntt_convolute(a, b) == [1, 10, 16, 0])207assert(21 * 81 == (1*10**0 + 10*10**1 + 16*10**2 + 0*10**3))208209210