缘起

最近浏览<<我的第一本算法书>>(【日】石田保辉;宫崎修一)
本系列笔记拟采纳golang练习之

素性测试, 费马测试

素性测试是判断一个自然数是否为素数的测试。素数(prime number)就是只能被1和其本身整除,且大于1的自然数。目前在加密技术中被广泛应用的RSA算法就会用到大素数,因而“素性测试”在该算法中起到了重要的作用。费马测试被称为概率性素性测试,它判断的是“某个数是素数的概率大不大”。对于任意素数p, 以及小于p的自然数n, 必然有: (n^p) % p = n,这就是"费马小定理"。依据是否满足费马小定理来判断一个数是否为素数的办法就是“费马测试”。摘自 <<我的第一本算法书>> 【日】石田保辉;宫崎修一

  • 费马测试是素性测试的必要非充分条件
  • 因为素数在所有自然数中的占比是多数, 因而面对大数区间时, 使用费马测试能够大大减速素性测试的判断

疾速幂取余

  • 费马测试须要计算n的p次幂, n是任意小于p的自然数, p通常是大数, 因而计算结果十分微小, 很容易溢出
  • 可依据数学定理将大数合成为屡次小数的计算: 积的余=余的积取余, 即 (ab)%p = ((a%p)(b%p)) % p

设计

  • IPrimeTester: 素性测试器接口
  • tSimplePrimeTester: 循环整除法进行素性测试,. 实现IPrimeTester接口
  • tFermatTester: 费马测试器, 实现IPrimeTester接口

单元测试

fermat_test.go, 验证和比照循环整除法和费马测试的效率, 尤其是大于2^32以上的大整数

package othersimport (    "fmt"    "learning/gooop/others/fermat_test"    "testing"    "time")func Test_FermatTest(t *testing.T) {    fnAssertTrue := func(b bool, msg string) {        if !b {            t.Fatal(msg)        }    }    fnTestPrime := func(tester fermat_test.IPrimeTester) {        primes := []int{2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97}        set := make(map[int]bool, 0)        for _,v := range primes {            fnAssertTrue(tester.IsPrime(v), fmt.Sprintf("expecting %v is prime", v))            set[v] = true        }        for i := 0;i < 100;i++ {            if _,ok := set[i];!ok {                fnAssertTrue(!tester.IsPrime(i), fmt.Sprintf("expecting %v is not prime", i))            }        }    }    s := fermat_test.SimplePrimeTester    f := fermat_test.FermatPrimeTester    t.Log("testing SimplePrimeTester range 0-100")    fnTestPrime(s)    t.Log("testing FermatPrimeTester range 0-100")    fnTestPrime(f)    t.Log("testing range 100-100_000")    for i := 100;i < 100_000;i++ {        fnAssertTrue(s.IsPrime(i) == f.IsPrime(i), fmt.Sprintf("failed testing %v", i))    }    fnTestCost := func(tester fermat_test.IPrimeTester, from, to int) {        t0 := time.Now().UnixNano()        fnAssertTrue(tester.IsPrime(2147483647), "expecting 2147483647 is prime")        for i := from;i <= to;i++ {            tester.IsPrime(i)        }        cost := (time.Now().UnixNano() - t0) / 1000_000        t.Logf("cost = %v ms", cost)    }    t.Log("testing SimplePrimeTester range 0xffff_fffff000 to 0xffff_ffffffff")    fnTestCost(s, 0xffff_fffff000, 0xffff_ffffffff)    t.Log("testing FermatPrimeTester range 0xffff_fffff000 to 0xffff_ffffffff")    fnTestCost(f, 0xffff_fffff000, 0xffff_ffffffff)    t.Log(f)}

测试输入

因为质数在自然数中的占比是多数, 因而使用费马测试进行过滤, 能大大减速大数区间的质数筛选

$ go test -v fermat_test.go === RUN   Test_FermatTest    fermat_test.go:34: testing SimplePrimeTester range 0-100    fermat_test.go:36: testing FermatPrimeTester range 0-100    fermat_test.go:39: testing range 100-100_000    fermat_test.go:54: testing SimplePrimeTester range 0xffff_fffff000 to 0xffff_ffffffff    fermat_test.go:51: cost = 23752 ms    fermat_test.go:57: testing FermatPrimeTester range 0xffff_fffff000 to 0xffff_ffffffff    fermat_test.go:51: cost = 6 ms    fermat_test.go:59: Fermat(fail=94464, pass=9629)--- PASS: Test_FermatTest (23.88s)PASSok      command-line-arguments  23.885s

IPrimeTester.go

素性测试器接口

package fermat_testtype IPrimeTester interface {    IsPrime(int) bool}

tSimplePrimeTester.go

循环整除法进行素性测试,. 实现IPrimeTester接口

package fermat_testimport "math"type tSimplePrimeTester struct {}func newSimplePrimeTester() IPrimeTester {    return &tSimplePrimeTester{}}func (me *tSimplePrimeTester) IsPrime(x int) bool {    if x <= 1 {        return false    }    if x <= 3 {        return true    }    for i, q := 2,int(math.Floor(math.Sqrt(float64(x))));i <= q;i++ {        if x % i == 0 {            return false        }    }    return true}var SimplePrimeTester = newSimplePrimeTester()

tFermatTester.go

费马测试器, 实现IPrimeTester接口

package fermat_testimport "fmt"type tFermatTester struct {    iFailedCount int    iPassedCount int}func newFermatTester() IPrimeTester {    return &tFermatTester{}}var arrSampleNum = []int{ 1,2,3,4,5,6,7,8,9 }func (me *tFermatTester) IsPrime(x int) bool {    if x <= 1 {        return false    }    if x <= 3 {        return true    }    for i,size := 0, len(arrSampleNum);i < size;i++ {        x1 := x * arrSampleNum[i] / 10        if x1 <= 1 {            break        }        if !me.fermatTest(x1, x) {            me.iFailedCount++            return false        }    }    me.iPassedCount++    return SimplePrimeTester.IsPrime(x)}// 费马测试func (me *tFermatTester) fermatTest(n int, p int) bool {    // n^p % p == n ?    return n == fastMod(n, p, p)}// 疾速幂取余func fastMod(n int, p int, mod int) int {    sum := 1    for p > 0 {        if (p & 1) > 0 {            sum = (sum * n) % mod            p--        } else {            p /= 2            n = (n * n) % mod        }    }    return sum}func (me *tFermatTester) String() string {    return fmt.Sprintf("Fermat(fail=%v, pass=%v)", me.iFailedCount, me.iPassedCount)}var FermatPrimeTester = newFermatTester()

(end)