Haskell 大数的最后一位

Haskell 大数的最后一位,haskell,modulo,Haskell,Modulo,我在解决代码战 我设法找到了一种方法来计算奇数^奇数和奇数^偶数。但是我陷入了偶数^偶数/奇数中,因为数字与其幂的mod之间的关系并不明显 以下是我设法得到的: lastDigit::[Integer]->Integer lastDigit=(`rem`10)。去 哪里 go[]=1 go[x]=x go(x:y:r) |奇数x和奇数y=x^(go(y:r)`rem`(x+1)) |奇数x和偶数y=x^(折叠式y(go-r)(x+1)) |否则=--有什么提示吗? foldMod::Intege

我在解决代码战

我设法找到了一种方法来计算
奇数^奇数
奇数^偶数
。但是我陷入了偶数^偶数/奇数中,因为数字与其幂的mod之间的关系并不明显

以下是我设法得到的:

lastDigit::[Integer]->Integer
lastDigit=(`rem`10)。去
哪里
go[]=1
go[x]=x
go(x:y:r)
|奇数x和奇数y=x^(go(y:r)`rem`(x+1))
|奇数x和偶数y=x^(折叠式y(go-r)(x+1))
|否则=--有什么提示吗?
foldMod::Integer->Integer->Integer->Integer
foldMod 0 0=1
foldMod基1模=基'rem'模
foldMod基功率模=(基*foldMod基(功率-1)模)`rem`模

有人能给出一些关于如何处理偶数情况的提示吗?

我建议重新思考您的方法,并从一个更一般的函数开始。具体来说,你能计算吗

powMod :: Integer -> [Integer] -> Integer
其中,
powMod base exponents
计算问题mod
base
中描述的指数塔?请注意,当您递归时,您将使用不同的
基进行递归,因为各种第一指数的循环长度不一定都是
基的除数。例如,在以10为基数的情况下,任何第一个指数的最后一位数为每四个循环7次,而不是每十次;幂的最后一位数字如下所示:

x               0 1 2 3 4 5 6 7
7^x `mod` 10    1 7 9 3 1 7 9 3
您还需要注意第一个指数不在最终达到的周期中的情况;例如,在base 4中,我们有:

x              0 1 2 3 4 5 6 7
2^x `mod` 4    1 2 0 0 0 0 0 0

所以你不能只看
x`mod`1
就从中推断出
2^x`mod`4
是什么,即使周期长度是
1
。(还有其他的例子,如
2^x`mod`12
,其中周期大于1,但仍然没有原始的
2

你不需要计算整个数字就可以知道最后一个数字,有快速,而且速度较慢的方法可以计算最后一个数字,而不必担心所有其他数字

一种可以计算O(对数b)时间内ab的简单方法是通过使用以下等价物:

(a×b)mod m=((a mod m)×(b mod m))mod m

这意味着我们每次都可以计算最后一个数字,并使用它。因此,这意味着,只要我们能够表示最大为81的所有数字,我们就可以计算ab mod m
powMod m a b

powMod :: Int -> Int -> Int -> Int
powMod m = go
    where go _ 0 = 1
          go a b | even n = r
                 | otherwise = (x * r) `mod` m
              where r = go ((a*a) `mod` m) (div b 2) `mod` m
如果我们假设我们可以计算模,除以二,检查一个值是否为偶数,等等。在恒定时间内,这在O(logb)中运行

但通过寻找周期,我们甚至可以更快地做到这一点。假设我们必须计算7的幂,那么7^0是1,7^1是7,7^2 mod 10=9,等等。我们可以用乘法制作一个表格:

× │ 0 1 2 3 4 5 6 7 8 9 ──┼───────────────────── 0 │ 0 0 0 0 0 0 0 0 0 0 1 │ 1 2 3 4 5 6 7 8 9 2 │ 4 6 8 0 2 4 8 6 3 │ 9 2 5 8 1 4 7 4 │ 6 0 4 8 2 6 5 │ 5 0 5 0 5 6 │ 6 2 8 4 7 │ 9 6 3 8 | 4 2 9 | 1
因此,这意味着循环的长度为四。因此,这意味着如果我们必须计算7,例如374的幂,那么我们知道这是93个长度为4的循环,因此没有影响,两个额外的移动,因此我们知道7393的最后一个数字是9,而不必计算这个数字。由于此类循环的最大长度为10,因此可以在恒定时间内确定十进制数的最后一位。

提示:
(a*b)mod c=(a mod c)*(b mod c)mod c
您实际上可以计算O(1)中的最后一位(假设您可以在O(1)中执行模运算),通过分析重复相乘最终将如何产生一个“循环”。你能用语言说出你打算计算什么函数吗?
我已经盯着它看了一段时间了,还没有说服自己当前的方程对任何明显的解释都是正确的。@DanielWagner是的,我在重新思考和尝试其他方法后发现我的方法有问题_T@WillemVanOnsem我不相信这可以在O(1)中完成。请考虑<代码>数字(复制n 0)。
对于奇数vs.偶数
n
7^0=1
。我不确定这对你的答案有多大问题。@dfeuer:答案的其余部分假设7^0=1,我认为这是一个打字错误:s。@dfeuer:但这些不是幂,而是乘法。然后用于第二个表。我认为这与t的有趣部分无关特别是:即使首先计算传递给您的
powMod
的指数也是昂贵的(并且可能不适合
Int
),而且您没有解决使其更便宜的问题。(例如,你需要计算几个小于10的模的周期,你不需要谈论这个。我认为你还需要执行一个操作,有效地检查指数塔是否至少与给定的数字一样大,以处理一些周期不能立即开始的问题。)@DanielWagner:但是你不需要计算整个指数,因为你只需要找出“循环”的长度。例如,如果我们必须计算3^(4^5),那么我们知道3有一个四的循环。所以我们只对(4^5)的模感兴趣(“如果你想,基数为4的数字中的最后一位”),然后我们计算因此,我们不仅减少了(3^…)的计算量,而且还减少了(4^5)本身的计算量。 power │ │ last digit ────────────────────────── 0 │ │ 1 1 │ 7*1 │ 7 2 │ 7*7 │ 9 3 │ 7*9 │ 3 4 │ 7*3 │ 1
1  →  7  →  9  →  3
 ↖_______________/