大数的模数

Modulus of a large number

我正在尝试计算 T-SQL 中非常大的数(> 38 位)的模数。

我曾经将我的变量转换为数字,但现在这个数字太大了,它抛出了一个错误:算术溢出错误将 varchar 转换为数字数据类型。

例如,我想知道我应该如何继续得到这个结果: 17448000012524221015281629272289115277 % 97(在这种情况下结果应该是 1)

感谢您的帮助。

您可以根据模属性将长整数拆分为多个部分来计算模数:

(a + b) mod n = [(a mod n) + (b mod n)] mod n.

ab mod n = [(a mod n)(b mod n)] mod n.

17448000012524221015281629272289115277 = 17448000012524221015281629 * 1000000000000 + 272289115277

所以

select ((17448000012524221015281629 % 97)*(1000000000000 % 97) + 272289115277 % 97) % 97 as modulo

尝试:

DECLARE @Dividend VARCHAR(100) = '17448000012524221015281629272289115277'
DECLARE @Divisor BIGINT = 97

DECLARE @ChunkSize INT = 10  -- Must be >= 1 and < roughly Log10(bigint max / @Divisor)
DECLARE @Base BIGINT = CONVERT(BIGINT, '1' + REPLICATE('0', @ChunkSize))  -- 10 ^ ChunkSiae
DECLARE @PaddedSize INT = CEILING(LEN(@Dividend) * 1.0 / @ChunkSize) * @ChunkSize 
DECLARE @PaddedValue VARCHAR(100) = RIGHT(REPLICATE('0', @ChunkSize) + @Dividend, @PaddedSize)

DECLARE @Remainder BIGINT = 0
WHILE (LEN(@PaddedValue) > 0)
BEGIN
    DECLARE @PartValue BIGINT = CONVERT(BIGINT, LEFT(@PaddedValue, @ChunkSize))
    SET @Remainder = (@Remainder * @Base + @PartValue) % @Divisor
    SET @PaddedValue = STUFF(@PaddedValue, 1, @ChunkSize, '')
END

SELECT @Remainder

如果分红值可能为负,则需要提取符号并调整所得余数。

这里的解决方案是,当数字太大时,将其切割以计算模数97。

问题是每个 97 的 10 次方都会有 0 作为模数 97

    970%97=0
   9700%97=0
  97000%97=0
 970000%97=0

例如
( 12345 )%97 可以拆分为
( (123 %97)*100 + 45 )%97

select *

, case 
  when len(bignum)>=38
  then ((cast(left(bignum, len(bignum)-18) as decimal(38,0))%97)
       * cast(power(1e1,18) as decimal(38,0))
       + cast(right(bignum, 18) as decimal(38,0)))%97
  else cast(bignum as decimal(38,0))%97
  end as mod97

from (values
('17448000012524221015281629272289115277'), 
('100'), 
('97000000000000000000000000000000000000000000000000000001')
) q(bignum); 
bignum mod97
17448000012524221015281629272289115277 77
100 3
97000000000000000000000000000000000000000000000000000001 1

db<>fiddle here