ashleytgg 发表于 2020-2-23 15:11:45

用辗转相除法求自然数e关于模φ的逆

本帖最后由 ashleytgg 于 2020-2-23 15:32 编辑

欧几里得的辗转相除除法是数论中最基本的定律,但我用lisp 把它结合起来,觉得还是很有点乐趣,所有和大家分享下。
;;用辗转相除法 求两个自然数的 最大公约数相对应的lsp 函数为 (gcd a b)


;; output_mode 为输出方式,默认状态下输出 最大公约数,否则输出 辗转相除法的点对
(defun seek_greatest_common_divisor
       (a b output_mode / temp r group_pair)
(if (< a b)
    (setq temp a
    a b
    b temp

    )
)
(setqgroup_pair
   (list (list a b))
)
(while (/= (setq r (rem a b))
       0
   )
    (setq a b
    b r
    group_pair
   (cons (list a b) group_pair)
    )
)
(setq group_pair (reverse group_pair))
(if output_mode
    group_pair
    b
)
)
;;   ( seek_greatest_common_divisor   (*2 3 5 7)(* 137 7 59 3 ) t )
;;   (gcd (*2 3 5 7)(* 137 7 59 3 )   )
;;( seek_greatest_common_divisor3120 17 t )

;; 定义一个二元列表(a b) 乘以一个数 (a b)* c = (ab bc)
(defun XC (lst c /)
(list(* (car lst) c)
(* (cadr lst) c)
)
)
;;定义一个二元列表相加的函数
(defun ++ (lst1 lst2 lst3 / lst)
(mapcar '+ lst1 lst2 lst3)
)



;; 求 一次整数方程 ed + kφ= 1的解 , 其中 e 和 φ 是 互素的
;; (setq e 79φ_module 3120 )
(defun seek_inverse_of_module
            (e φ_module / group lst i x y d)
(if (or (null e)
    (null φ_module)
      )
    (setq e 17
    φ_module 3120
    )
)
;; 把e 限制在 模φ_module 的最小剩余系内
(setq e (rem e φ_module))
;; 当 (e φ_module) 是互质数时,程序进入计算,否则ed ≡1 (mode φ_module ) 无解
(if (and (= (gcd e φ_module) 1)
   (/= e 1)
      )
    (progn
      (setq
;; 用辗转相除法 求出 312017 的点对group ( (3120 17) (17 9) (9 8) (8 1) )
group
      (seek_greatest_common_divisor e φ_module t)
group (reverse group)
;; 当group((8 1) (9 8) (17 9) (3120 17))第一一个元素 8能够整除1 时,去掉这个元素,为了程序计算需要
group (cdr group)
;; 把group((9 8) (17 9) (3120 17))中每个元素比如 3120/17 的商183加入到 (3120 17 183)
group
      (mapcar '(lambda (lst / dividend divisor)
       (mapcar 'set '(dividend divisor) lst)
       (list dividend divisor (/ dividend divisor))
         )
          group
      )
      )
      ;|程序说明:
    用辗转相除法求方程 ed + kφ= 1 的e 关于模 φ 的逆
   group 结构为 ( (9 8 1) (17 9 1) (3120 17 183))   
      9= 3120 + 17*(-183)
         8= 17 + 9* (-1)
答案1:1 = 9*(1) + 8* (-1)    ==> 1 = 9 + * (-1)      
                  答案2:==> 1= 17* (-1) + 9* 2                  
                           ==> 1= 17* (-1) + *2
                  答案3: ==> 1= 3120*2+17* (-367)            
答案1 、答案2、答案3 的解系数为: ( (1 -1) (-1 2) (2 -367) )
|;
      (setq i 0)
      (mapcar '(lambda (lst / dividend divisor quotient lst_2)
   (mapcar 'set '(dividend divisor quotient) lst)
   ;; x y dividend divisor 之间的关系( dividend divisor)* (x y)T =1
   (if (= i 0)
       ;; lst 为 group 的初始项时
       (setq x 1
       y (* -1 quotient)
       )
       (progn
         (setq lst_2 (++
         (XC (list 0 divisor) x)
         (XC (list dividend 0) y)
         (XC (list 0 (* -1 divisor quotient))
            y
         )
         )
         x   (/ (car lst_2) dividend)
         y   (/ (cadr lst_2) divisor)
         )
       )
   )
   ;| 当lst 不是group 中的 第一项时
         (dividend divisor)* (x y)T ==(dividend_前 (dividend-divisor*商) )(x y)T      
            而 divisor_前 前一项的被除数 就等于当前项的 除数 divisor
            |;
   (setq i (1+ i))
   (list x y)
         )
      group
      )
      ;;方程 ey ≡1 (mode φ_module ) 的e 关于模 φ 的逆 为 y
      (cond
((< (rem y φ_module) 0)
   (+ (rem y φ_module) φ_module)
)
((> (rem y φ_module) φ_module)
   (- (rem y φ_module) φ_module)
)
(t
   (rem y φ_module)
)
      )
    )
    ;;当 (e φ_module) 不是互质数时 或 e =1 时
    (progn
      (cond
((= e 1)
   (setq y 1)
)
(t
   (princ "您说输入的参数无解!\n")
)
      )
    )
)
;; (if(and (= (gcd e φ_module) 1)   函数结束
)
;|(defun seek_inverse_of_module函数结束 )   (defun seek_inverse_of_module函数结束 )   (defun seek_inverse_of_module函数结束 )
      (setq φ_module 3120)(setq φ_module 11018)
      ;; 验证程序的正确性
      (mapcar '(lambda (e)
   (setq
       d (seek_inverse_of_module e φ_module)
   )
   (if (numberp d)
       (cond
         ((< (rem (* e d) φ_module) 0)
          (+ (rem (* e d) φ_module) φ_module)
         )
         ((> (rem (* e d) 3120) φ_module)
          (- (rem (* e d) 3120) φ_module)
         )
         (t
          (rem (* e d) φ_module)
         )
       )
       "无解"
   )
         )
      (list 4    1317    61    83    97113   151
      211    281379   509   683    91112171627
      21792909388169079209
       )
      )
   (seek_inverse_of_module 13120 )   
|;



(defun C:辗转相除法
      (/      dcl_file   dcl_id
         key    lst_         keys
         φ_module    group_residual_system
         i      group
      )
;; 定义一个用数组group_residual_system 填充列表框 "list_φ" 的函数
(defun add_list_list_φ (group_residual_system / i)
    (start_list "list_φ")
    (setq i 1)
    (mapcar '(lambda (x)
         (add_list (strcat "第" (itoa i) "个元素:" (itoa x)))
         (setq i (1+ i))
       )
      group_residual_system
    )
    (end_list)
)
;;   ( add_list_list_φgroup_residual_system )   

;; 定义一个函数求模φ_module 的最简剩余系
(defun create_residual_system(φ_module / group_residual_system i)

    (setq i 1
    group_residual_system
   nil
    )
    (repeat (1- φ_module)
      (if (= (gcd i φ_module) 1)
(setq group_residual_system
         (cons i group_residual_system)
)
      )
      (setq i (1+ i))
    )
    (reverse group_residual_system)
)
;; (setq group_residual_system (create_residual_systemφ_module))   

(vl-load-com)
;; 创建一个dcl临时文件,并加载该文件,返回关键字 dcl_id
(setq dcl_id (create_tmp_dcl))
(new_dialog "tang_dcl" dcl_id)
(setqφ_module      (read (get_tile "φ"))
;; 求模φ_module 的 最简剩余系
group_residual_system (create_residual_system φ_module)
)
;; 对列表框"list_φ" 进行填充
(add_list_list_φ group_residual_system)
;; 对txt 控件 "tang1" 进行赋值
(set_tile "tang1"
      (strcat "模" (itoa φ_module) "的最简剩余系:")
)
(set_tile "tang2"
      (strcat "共" (itoa (length group_residual_system)) "个元素")
)
;;定义各控件 的动作函数
(foreach key '("list_φ" "cacuate" "φ" "e")
    (action_tile key "(Action_辗转相除法$key $value )")
)
(defun Action_辗转相除法 (key value / lst)
    (cond
      ((= key "list_φ")
       (setq e (nth (read value) group_residual_system))
       (mapcar '(lambda(x value)
      (set_tile x value)
    )
         (list "e" "d")
         (list (itoa e) "")
       )
      )
      ;; 计算按钮的动作函数 求ed ≡1 (mode φ_module ) 的解 d
      ((= key "cacuate")
       (setq e         (get_tile "e")
       φ_module (read (get_tile "φ"))
       )
       (if (and
       ;; (read value) 是数值
       (numberp (VL-CATCH-ALL-APPLY
      'read
      (list e)
          )
       )
       ;; (read value) 是整数
       (= (type (setq e (read e))) 'int)
       ;; (read value) 是>1 的整数
       (> e 0)
   )
   (progn
   (setq
       d (seek_inverse_of_module e φ_module)
   )
   (if (numberp d)
       (set_tile "d" (itoa d))
       ;; 当 ed ≡1 (mode φ_module )无解时
       (set_tile "d" "无解")
   )
   )
   (progn
   (alert "你的输入的e有误,请重新输入!")
   (mode_tile "e" 2)
   )
       )
       ;;if(and(numberp (VL-CATCH-ALL-APPLY   
      )
      ;;编辑框"φ" 的动作函数
      ((= key "φ")
       (if (and
       ;; (read value) 是数值
       (numberp (VL-CATCH-ALL-APPLY
      'read
      (list value)
          )
       )
       ;; (read value) 是整数
       (= (type (read value)) 'int)
       ;; (read value) 是>1 的整数
       (> (read value) 1)
   )
   ;; 当value 是 整数时
   (progn
   ;; 对txt 控件 "tang1" 进行赋值
   (set_tile "tang1"
         (strcat "模" value "的最简剩余系:")
   )
   (setq
       group_residual_system
      (create_residual_system (read value))
   )
   ;; 对列表框"list_φ" 进行填充 ,当group_residual_system 的个数大于1万个时,只填充前1万项
   (if (< (length group_residual_system) 10000)
       (add_list_list_φ group_residual_system)
       (progn
         (setq group nil)
         (repeat 10000
   (setq group (cons 0 group))
         )
         ;; 取group_residual_system 中的前1万项
         (add_list_list_φ
   (mapcar '+ group_residual_system group)
         )
         (set_tile
   "tang3"
   "只显示前1万项!"
         )
       )
       ;;(if (< (length group_residual_system) 10000)
   )
   ;; (if (> (length group_residual_system) 10000)
   (set_tile
       "tang2"
       (strcat "共"
         (itoa (length group_residual_system))
         "个元素"
       )
   )
   )
   ;; progn 函数结束
   (progn
   ;; 当value 不是整数,或者是等于1 时
   (alert "你的输入有误,请重新输入!")
   (mode_tile key 2)
   )
       )
       ;;if(and(numberp (VL-CATCH-ALL-APPLY
       (set_tile "d" "")
      )
      ;;编辑框"φ" 的动作函数 结束
      ((= key "e")
       (set_tile "d" "")
      )
    )
    ;;cond 函数结束

)
;; (defun Action_辗转相除法 (key value
(setq Dialog_Return (start_dialog))
(unload_dialog dcl_id)

)
;; (defun C:辗转相除法函数结束





;; 创建一个临时dcl 文件 ,并打开它,返回关键字dcl_id
(defun create_tmp_dcl (/ f TMPDCL dcl_id)
(setqgroup_str
   '(""
   "tang_dcl:dialog"
   "{"
   "    label = \"用欧几里得辗转相除法解同余方程:ed ≡1 (mode φ) \" ;"
   "    spacer;"
   "    :boxed_row"
   "    {"
   "      alignment = centered ;"
   "      children_fixed_width = true ;"
   "      fixed_height = true ;"
   "      fixed_width = true ;"
   "      :column"
   "      {"
   "            :text"
   "            {"
   "                label = \"模φ的最简剩余系:\" ;"
   "                key =\"tang1\" ;"
   "            }"
   "            :text"
   "            {"
   "                label = \"共8个元素\" ;"
   "                key =\"tang2\" ;"
   "            }"
   "            :text"
   "            {"
   "                label = \"\" ;"
   "                key =\"tang3\" ;"
   "            }"
   "            :list_box"
   "            {"
   "                fixed_height = false ;"
   "                fixed_width = true ;"
   "                is_tab_stop = true ;"
   "                key = \"list_φ\" ;"
   "                width = 20 ;"
   "            }"
   "      }"
   "      :column"
   "      {"
   "            fixed_height = true ;"
   "            :edit_box"
   "            {"
   "                edit_width = 8 ;"
   "                is_enabled = true ;"
   "                key = \"e\" ;"
   "                label = \"方程ed ≡1 (mod φ)的e\" ;"
   "                value=\"17\" ;"
   "            }"
   "            :edit_box"
   "            {"
   "                edit_width = 8 ;"
   "                key = \"φ\" ;"
   "                label = \"方程ed ≡1 (mod φ)的φ\" ;"
   "                value=\"3120\" ;"
   "            }"
   "            :row"
   "            {"
   "                :button"
   "                {"
   "                  key = \"cacuate\" ;"
   "                  fixed_width = true ;"
   "                  label = \"计算e对模φ的逆: d\" ;"
   "                  width = 6 ;"
   "                }"
   "                :edit_box"
   "                {"
   "                  edit_width = 8 ;"
   "                  key = \"d\" ;"
   "                  label = \"\" ;"
   "                }"
   "            }"
   "      }"
   "    }"
   "    :row"
   "    {"
   "      alignment = centered ;"
   "      children_fixed_width = true ;"
   "      fixed_width = true ;"
   "      spacer_1;"
   "      :button"
   "      {"
   "            is_cancel = true ;"
   "            key = \"cancel\" ;"
   "            label = \"取消\" ;"
   "            width = 15 ;"
   "      }"
   "    }"
   "}"
    )
)
(SETQ TMPDCL (VL-FILENAME-MKTEMP "tmp" "" ".dcl"))
(setq f (open tmpdcl "w"))
(foreach str group_str
    (write-line str f)
)
(close f)
(setq dcl_id (load_dialog TMPDCL))
(vl-file-delete TMPDCL)
dcl_id
)
;;( create_tmp_dcl )

mahuan1279 发表于 2020-2-23 22:26:26

好好学习下~~~

ashleytgg 发表于 2020-2-24 11:14:16

:handshake,
页: [1]
查看完整版本: 用辗转相除法求自然数e关于模φ的逆