다음은 초등학교에서 배우는 나눗셈 계산표를 만들어주는 OCaml 소스 코드이다.
나눗셈 계산표를 완성하고 나서 약수, 배수 관계를 알려준다.

아래의 소스는 Python 용 소스를 F# 용 소스로 거의 일대일 변환하고,또 F# 소스를 OCaml 소스로 변환한 것이라서, OCaml 언어의 명령형 언어의 특징을 위주로 짜여져 있다.

예외상황 처리 부분 try ... with ... 부분이 아직 미완성이다.

  1. (*
  2.  *  Filename: makeDivisionTable.ml
  3.  *
  4.  *  Purpose:  Make a division table in a handy written form.
  5.  *
  6.  *  Execute: ocaml makeDivisionTable.ml
  7.  *
  8.  *   Or
  9.  *
  10.  *  Compile: ocamlc -o makeDivisionTable.exe makeDivisionTable.ml
  11.  *  Execute: makeDivisionTable 12345 32
  12.  *           makeDivisionTable 500210 61
  13.  *           makeDivisionTable 234 55
  14.  *
  15.  *     Date:  2013. 2. 2.
  16.  *   Author:  pkim __AT__ scripts.pe.kr
  17.  *)
  18. open Printf ;;
  19. exception RuntimeError of string
  20. exception ValueError of string
  21. let sBASE36 = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ" ;;
  22. let sSPACE = "                                                          "  ;;
  23. let sULINE = "__________________________________________________________"  ;;
  24. let sHIPHEN = "----------------------------------------------------------"  ;;
  25. let println s = printf "%s\n" s ;;
  26. let print s = printf "%s" s ;;
  27. let printUsage() =
  28.     (* print("Using: makeDivisionTable [numerator] [denominator]")  *)
  29.     (* print("Make a division table in a handy written form.") *)
  30.     println "사용법: makeDivisionTable [피제수] [제수]" ;
  31.     println "손으로 작성한 형태의 나눗셈 표를 만들어준다." ;;
  32. let simplify v width =
  33.     let t = [| string_of_int v |] in
  34.     let slen = (String.length t.(0)) in
  35.     if slen < width then begin
  36.         t.(0) <- (String.sub sSPACE 0 (width - slen)) ^ t.(0)
  37.     end ;
  38.     t.(0) ;;
  39. let getSuffix v =
  40.     let t = v mod 10  in
  41.     let suffix = [| "은" |] in
  42.     if (String.contains "2459" (string_of_int  t).[0]) then begin
  43.         suffix.(0) <- "는" ;
  44.     end ;
  45.     suffix.(0) ;;
  46. let makeTable numer denom quotient =
  47.     let strNumer = sprintf "%d" numer in
  48.     let strDenom = sprintf "%d" denom  in
  49.     let strQuotient = sprintf "%d" quotient  in
  50.     let lenN = String.length strNumer  in
  51.     let lenD = String.length strDenom  in
  52.     let lenQ = String.length strQuotient  in
  53.     let offsetLeft = 3 + lenD + 3  in
  54.     let spaces = "                                                                                 "  in
  55.     let uline  = String.sub sULINE 0 (lenN + 2)  in
  56.     let sline  = String.sub sHIPHEN 0 lenN  in
  57.     let bias = lenN - lenQ  in
  58.     println ((String.sub spaces 0 offsetLeft) ^ (String.sub spaces 0 bias) ^ (sprintf "%d" quotient)) ;
  59.     println ((String.sub spaces 0 (offsetLeft - 2)) ^ uline) ;
  60.     print ("   " ^ strDenom ^ " ) " ^ strNumer) ;
  61.     let strTmpR = [| String.sub strNumer 0  (bias + 1) |] in
  62.     let tmpR = ref (int_of_string strTmpR.(0))  in
  63.     let tmpSub = ref 0  in
  64.     let oneDigit = [| "" |] in
  65.     for i = 0 to (lenQ - 1) do
  66.         if (String.sub strQuotient i 1) = "0" then begin
  67.             if i + 1 < lenQ then begin
  68.                 oneDigit.(0) <- (String.sub  strNumer (bias + i + 1) 1) ;
  69.                 printf "%s" oneDigit.(0)  ;
  70.                 strTmpR.(0) <- (strTmpR.(0) ^ oneDigit.(0)) ;
  71.                 tmpR := int_of_string strTmpR.(0)
  72.             end
  73.         end
  74.         else  begin
  75.             print_newline() ;
  76.             tmpSub := (int_of_string (String.sub strQuotient i 1)) * denom ;
  77.             printf "%s\n" ((String.sub spaces 0 offsetLeft) ^ (simplify !tmpSub  (bias + i + 1)))  ;
  78.             printf "%s\n" ((String.sub spaces 0 offsetLeft) ^ sline)  ;
  79.             tmpR := !tmpR - !tmpSub  ;
  80.             if !tmpR = 0 && i + 1 < lenQ then begin
  81.                 printf "%s" ((String.sub spaces 0 offsetLeft) ^ (String.sub spaces 0 (bias + i + 1)) ) ;
  82.             end
  83.             else begin
  84.                 printf "%s" ((String.sub spaces 0 offsetLeft) ^ (simplify !tmpR (bias + i + 1))) ;
  85.             end ;
  86.             strTmpR.(0) <- sprintf "%d" !tmpR ;
  87.             if i + 1 < lenQ then begin
  88.                 oneDigit.(0) <- (String.sub strNumer (bias + i + 1) 1) ;
  89.                 if  (String.length oneDigit.(0)) > 0 then
  90.                     print oneDigit.(0) ;
  91.                 strTmpR.(0) <- (strTmpR.(0) ^ oneDigit.(0))
  92.             end ;
  93.             tmpR := int_of_string strTmpR.(0)
  94.         end
  95.     done ;
  96.     printf "\n" ;
  97.     !tmpR ;;
  98. let main() =
  99.     let cmdArgs = Sys.argv in
  100.     if (Array.length cmdArgs < 3 || "-h" = cmdArgs.(1)) then begin
  101.         printUsage() ;
  102.         exit(1)
  103.     end ;
  104.     let a = [| 0 |] in
  105.     let b = [| 1 |] in
  106.     (*
  107.     try begin
  108.         a.(0) <- int_of_string (cmdArgs.(1)) ;
  109.         b.(0) <- int_of_string (cmdArgs.(2)) ;
  110.     end
  111.     with
  112.         | Failure e ->  ( begin
  113.                               printf "피제수: %s, 제수: %s\n" (cmdArgs.(1)) (cmdArgs.(2));
  114.                               printf "숫자 입력에 오류가 있습니다.\n";
  115.                               (* exit(1);  *)
  116.                         end; ) ;
  117.     *)
  118.    
  119.     a.(0) <- int_of_string (cmdArgs.(1)) ;
  120.     b.(0) <- int_of_string (cmdArgs.(2)) ;
  121.     if a.(0) <= 0 then begin
  122.         printf "피제수: %d\n" a.(0) ;
  123.         printf "피제수는 양의 정수라야 합니다.\n" ;
  124.         exit(1)
  125.     end
  126.     else if b.(0) <= 0 then begin
  127.         printf "제수: %d\n" b.(0) ;
  128.         printf "제수는 양의 정수라야 합니다.\n" ;
  129.         exit(1)
  130.     end ;
  131.     let q = a.(0) / b.(0) in
  132.     let r = a.(0) mod b.(0) in
  133.     printf "나눗셈 %d ÷ %d 의 결과: " a.(0) b.(0) ;
  134.     printf "몫: %d, " q ;
  135.     printf "나머지: %d\n" r ;
  136.     print_newline();
  137.     let k = makeTable a.(0) b.(0) q in
  138.     if k = r then
  139.         printf "\n나머지: %d\n" k ;
  140.     if k = 0 then begin
  141.         printf "%d = %d x %d\n" a.(0) b.(0) q  ;
  142.         printf "%d%s %d의 배수(mupltiple)이다.\n" a.(0) (getSuffix a.(0)) b.(0)  ;
  143.         printf "%d%s %d의 약수(divisor)이다.\n" b.(0) (getSuffix b.(0)) a.(0)
  144.     end
  145.     else begin
  146.         printf "%d = %d x %d + %d\n" a.(0) b.(0) q r  ;
  147.     printf "%d%s %d의 배수(mupltiple)가 아니다.\n" a.(0) (getSuffix a.(0)) b.(0)
  148.     end ;;
  149. main();;




컴파일> fsc --codepage:949   MakeDivisionTable.fs

실행> MakeDivisionTable.py 500210 61
나눗셈 500210 ÷ 61 의 결과: 몫: 8200, 나머지: 10

          8200
      ________
   61 ) 500210
         488
        ------
         122
         122
        ------
            10

나머지: 10
500210 = 61 x 8200 + 10
500210은 61의 배수(mupltiple)가 아니다.



 

Posted by Scripter
,

자리수가 매우 긴 정수(큰 정수, big integer)를 계산하려면

C/C++ 언어로는 gmp 또는 mpir 라이브러리를 쓰면 되고

Java 언어로는 java.math.BigInteger 클래스를 사용하면 되고,

C# 언어로는 System.Numerics.BigInteger 클래스를 사용하면 되고,

Python 언어로는 long 타입(Python 이 자체적으로 알아서 int 타입과 long 타입을 자동 변환함)을쓰면 되고,

Haskell 언어로는 (Int 타입 대신) Integer 타입을 쓰면 된다.

F# 언어의 경우에는 F 샤프 를 참조한다,

 

그렇다면 OCaml 언어로는 big integer 계산을 어떻게 할까?

답은 의외로 간단하다. 이미 lib 폴더에 설치되어 있는 라이브러리 nums.cma 를 불러 쓰면 된다.

toplevel 에서 사용하거니 ocaml 로 스크립트를 실행할 때는 디렉티브 구문 #load "nums,cma" 를 사용하면 된다. 그러나 ocamlc 명령을 컴파일할 때는 이 디렉티브가 통하지 않으니 이 디렉토리 구문을 주석 처리 하고 컴파일하는 명령줄에 nums.cma 를 추가하면 된다. 이 디렉티브가 없더라도 ocaml 명령으로 스크립트를 실행하는 명령줄에 nums.cma 를 추가하면 된다. 명령 줄에 이를 추가하지 않으면, 정의되지 않은 전역적인(global) Num 을 참조한다는 에러 메시지가 뜬다.

Error: Reference to undefined global `Num'

OCaml 언어에서 big integer 타입의 사칙 연산 기호는 +, -, *, / 가 아니라 +/, -/. */. // 이다. (연산 기호 모두 / 문자가 하나씩 더 붙는다.)

 

1) 스크립트로 실행하기

    프롬프트> ocaml nums.cma calcBigFactorial.ml

 

2) 컴파일한 후 실행하기

    프롬프트> ocamlc -o calcBigFactorial.exe nums.cma calcBigFactorial.ml

    프롬프트> calcBigFactorial

 

(*
 *  Filename: calcBigFactorial.ml
 *
 *       Purpose: Caculation big integers and big rationals with OCaml language.
 *
 *   Execute: ocaml nums.cma calcBigFactorial.ml
 *
 *    Or
 *
 *   Compile: ocamlc -o calcBigFactorial.exe nums.cma calcBigFactorial.ml
 *   Execute: calcBigFactorial.exe
 *
 *    See: http://caml.inria.fr/resources/doc/faq/core.en.html
 *    Date: 2013. 1. 30.
 *)

(* #load "nums.cma";; *)   (* This line works in the toplevel of OCaml *)

open Num;;
open Format;;   (* This is reauired for printf *)

(* let print_num ff n = fprintf ff "%s" (string_of_num n);; *)

let rec fact n =
   if n <= 0 then (num_of_int 1) else num_of_int n */ (fact (n - 1));;

let x = 100
in
    printf "%d! = %s\n" x (string_of_num (fact x));;


(*
Output:
100! = 9332621544394415268169923885626670049071596826438162146859296389521759999
32299156089414639761565182862536979208272237582511852109168640000000000000000000
00000
*)

 

 

 

Posted by Scripter
,

ASCII(애스키)란 American Standard Code for Information Interchange의 줄임글로서, 영문자에 기초한 문자 인코딩이다.  이 문자 인코딩에는 C0 제어문자(C0 control character)도 포함되어 있다.  ( 참고:  ASCII - Wikipedia, the free encyclopedia )

다음은  7bit ASCII 코드표를 만들어 보여주는 OCaml 소스 코드이다. 소스 코드 중에 진법변환에 필요한 함수

                atoi string  radix
                itoa number radix

를 OCaml 코드로 자체 작성하여 사용하였다.

(아래의 소스는 Python 소스를 F# 소스로 일대일 변환 수정하고, 또 F# 소스를 OCaml 소스로 바꾼 것이라서 명령형 언어 특징을 위주로 작성되어 있다. 그래서 함수형 언어의 관점으로 보면 사이드 이팩트가 많아 난잡하게 보이는 소스이다.)

  1. (*
  2.  *  Filename: makeAsciiTable.ml
  3.  *            Make a table of ascii codes.
  4.  *
  5.  *  Execute: ocaml makeAsciiTable.ml
  6.  *
  7.  *    Or
  8.  *
  9.  *  Compile: ocamlc -o makeAsciiTable.exe makeAsciiTable.ml
  10.  *  Execute: makeAsciiTable
  11.  *
  12.  *      Date:  20013. 1. 29.
  13.  *    Author:  pkim __AT__ scripts.pe.kr
  14.  *)
  15. open Printf;;
  16. exception RuntimeError of string
  17. exception ValueError of string
  18. let println s = printf "%s\n" s ;;
  19. let print s = printf "%s" s ;;
  20. let printUsage() =
  21.     println "Usage: makeAsciiTable" ;
  22.     println "Make a table of ascii codes." ;;
  23. let split_char sep str =
  24.   let rec indices acc i =
  25.     try
  26.       let i = succ(String.index_from str i sep) in
  27.       indices (i::acc) i
  28.     with Not_found ->
  29.       (String.length str + 1) :: acc
  30.   in
  31.   let is = indices [0] 0 in
  32.   let rec aux acc = function
  33.     | last::start::tl ->
  34.         let w = String.sub str start (last-start-1) in
  35.         aux (w::acc) (start::tl)
  36.     | _ -> acc
  37.   in
  38.   aux [] is ;;
  39. let sBASE36 = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"  ;;
  40. let rec sdup str n =
  41.         match n with
  42.         | 0 -> ""
  43.         | k when k > 0 -> str ^ (sdup str (n - 1))
  44.         | _ -> ""
  45. let contains s1 s2 =
  46.   try
  47.     let len = String.length s2 in
  48.     for i = 0 to (String.length s1) - len do
  49.       if String.sub s1 i len = s2 then raise Exit
  50.     done;
  51.     false
  52.   with Exit -> true ;;
  53. let join list sep =
  54.     let rec join' list acc =
  55.         match list with
  56.             | [] -> ""
  57.             | [single] -> single
  58.             | one::[two] ->
  59.                         if acc = "" then one ^ sep ^ two
  60.                                     else acc ^ one ^ sep ^ two
  61.             | first::others -> join' others (acc ^ first ^ ", ")
  62.                                         in
  63.                                         join' list "" ;;
  64. let str_reverse str =
  65.     let len = String.length str in
  66.     let res = String.create len in
  67.     for i = 0 to pred len do
  68.         let j = pred len - i in
  69.         res.[i] <- str.[j]
  70.     done;
  71.     res ;;
  72. let itoa num radix =
  73.    let isNegative = ref false in
  74.    let num1 = num + 0 in
  75.    let numx = ref num1 in
  76.    if num < 0 then begin
  77.       isNegative := true ;
  78.       numx := (-num)
  79.    end ;
  80.    let nnumx = !numx in
  81.    let q1 = nnumx in
  82.    let q = ref q1 in
  83.    let r = ref 0 in
  84.    let slen = ref 1 in
  85.    while (!q >= radix) do
  86.        r := !q mod radix ;
  87.        q := !q / radix ;
  88.        slen := !slen + 1
  89.    done ;
  90.    let sslen = !slen in
  91.    let str = String.create sslen in
  92.    let p1 = nnumx in
  93.    let p = ref p1 in
  94.    for i = 0 to sslen - 1 do
  95.        r := !p mod radix ;
  96.        p := !p / radix ;
  97.        str.[i] <- sBASE36.[!r]
  98.    done ;
  99.    let str2 = str_reverse str in
  100.    str2;;
  101. let atoi s radix =
  102.     let ret = ref 0 in
  103.     let isNegative = ref false in
  104.     let len = String.length s in
  105.     let valx = ref 0 in
  106.     let c1 = s.[0] in
  107.     let c = ref c1 in
  108.     if !c = '-' then
  109.         isNegative := true
  110.     else if (!c >= '0' && !c <= '9') then
  111.         ret := (int_of_char !c) - (int_of_char '0')
  112.     else if (!c >= 'A' && !c <= 'Z') then
  113.         ret := (int_of_char !c) - (int_of_char 'A') + 10
  114.     else if (!c >= 'a' && !c <= 'z') then
  115.         ret := (int_of_char !c) - (int_of_char 'a') + 10 ;
  116.     if (!ret >= radix) then
  117.         raise (ValueError (sprintf "Can not read \"%s\" (as radix %d): '%c' is invalid." s radix !c ) ) ;
  118.     for i = 1 to len - 1 do
  119.         c := s.[i] ;
  120.         ret := (!ret)*radix  ;
  121.         if (!c >= '0' && !c <= '9') then
  122.             valx := int_of_char !c - int_of_char '0' 
  123.         else if (!c >= 'A' && !c <= 'Z') then
  124.             valx := int_of_char !c - int_of_char 'A' + 10
  125.         else if (!c >= 'a' && !c <= 'z') then
  126.             valx := int_of_char !c - int_of_char 'a' + 10 ;
  127.         if (!valx >= radix) then
  128.             raise (ValueError (sprintf "Can not read \"%s\" (as radix %d): '%c' is invalid." s radix !c ) ) ;
  129.         ret := (!ret) + (!valx)
  130.     done;
  131.     if (!isNegative) then
  132.         ret := (-(!ret) ) ;
  133.     !ret ;;
  134. let asc = [|
  135.     "NUL"; "SOH"; "STX"; "ETX"; "EOT";
  136.     "ENQ"; "ACK"; "BEL"; "BS"; "HT";
  137.     "LF"; "VT"; "FF"; "CR"; "SO";
  138.     "SI"; "DLE"; "DC1"; "DC2"; "DC3";
  139.     "DC4"; "NAK"; "SYN"; "ETB"; "CAN";
  140.     "EM"; "SUB"; "ESC"; "FS"; "GS";
  141.     "RS"; "US"; "Spc" |] ;;
  142. let control = [|
  143.     "NUL (null)";
  144.     "SOH (start of heading)";
  145.     "STX (start of text)";
  146.     "ETX (end of text)";
  147.     "EOT (end of transmission)";
  148.     "ENQ (enquiry)";
  149.     "ACK (acknowledge)";
  150.     "BEL (bell)";
  151.     "BS  (backspace)";
  152.     "TAB (horizontal tab)";
  153.     "LF  (line feed, NL new line)";
  154.     "VT  (vertical tab)";
  155.     "FF  (form feed, NP new page)";
  156.     "CR  (carriage return)";
  157.     "SO  (shift out)";
  158.     "SI  (shift in)";
  159.     "DLE (data link escape)";
  160.     "DC1 (device control 1)";
  161.     "DC2 (device control 2)";
  162.     "DC3 (device control 3)";
  163.     "DC4 (device control 4)";
  164.     "NAK (negative acknowledge)";
  165.     "SYN (synchronous idle)";
  166.     "ETB (end of trans. block)";
  167.     "CAN (cancel)";
  168.     "EM  (end of medium)";
  169.     "SUB (substitute, EOF end of file)";
  170.     "ESC (escape)";
  171.     "FS  (file separator)";
  172.     "GS  (group separator)";
  173.     "RS  (record separator)";
  174.     "US  (unit separator)" |] ;;
  175. let makeTable() =
  176.     let sbuf = "    " in
  177.     let sbuf = sbuf ^ (sdup "+----" 8) in
  178.     let sbuf = sbuf ^  "+" in
  179.     println sbuf ;
  180.     let sbuf = "    " in
  181.     let sbuf = sbuf ^  "| 0- " in
  182.     let sbuf = sbuf ^  "| 1- " in
  183.     let sbuf = sbuf ^  "| 2- " in
  184.     let sbuf = sbuf ^  "| 3- " in
  185.     let sbuf = sbuf ^  "| 4- " in
  186.     let sbuf = sbuf ^  "| 5- " in
  187.     let sbuf = sbuf ^  "| 6- " in
  188.     let sbuf = sbuf ^  "| 7- " in
  189.     let sbuf = sbuf ^  "|" in
  190.     println sbuf  ;
  191.     let sbuf = "+---" in
  192.     let sbuf = sbuf ^ (sdup "+----" 8) in
  193.     let sbuf = sbuf ^  "+" in
  194.     println sbuf ;
  195.     let aa = Array.make_matrix 16 8 "" in
  196.     for i = 0 to (16-1) do
  197.         let sbuf = (itoa i 16) in
  198.         let tbuf = "| " ^ sbuf ^ " " in
  199.         print tbuf ;
  200.         for j = 0 to (8-1) do
  201.            if j*16 + i <= 32 then
  202.                aa.(i).(j) <- sprintf "| %-3s" asc.(j*16 + i)
  203.             else if j*16 + i = 127 then
  204.                 aa.(i).(j) <- sprintf  "| %-3s" "DEL"
  205.             else begin
  206.                let c = char_of_int (j*16 + i) in
  207.                 aa.(i).(j) <- sprintf "|  %1c " c
  208.             end ;
  209.             print aa.(i).(j)
  210.         done;
  211.         println "|"
  212.     done ;
  213.     let sbuf = "+---" in
  214.     let sbuf = sbuf ^ (sdup "+----"  8) in
  215.     let sbuf = sbuf ^ "+" in
  216.     println sbuf ;
  217.     println "" ;
  218.     for i = 0 to (16-1) do
  219.         let tbuf = sprintf "%-30s  %-34s" control.(i) control.(i+16) in
  220.         println tbuf
  221.     done ;
  222.     "" ;;
  223. (* Begin here *)
  224. let main() =
  225.     let cmdArgs = Sys.argv in
  226.     if (Array.length cmdArgs > 1 && "-h" = cmdArgs.(1)) then  begin
  227.         printUsage() ;
  228.         exit(1)
  229.     end ;
  230.     makeTable() ;;
  231. main() ;;




컴파일> ocamlc -o makeAsciiTable.exe makeAsciiTable.ml

실행> makeAsciiTable

   
    +----+----+----+----+----+----+----+----+
    | 0- | 1- | 2- | 3- | 4- | 5- | 6- | 7- |
+---+----+----+----+----+----+----+----+----+
| 0 | NUL| DLE| Spc|  0 |  @ |  P |  ` |  p |
| 1 | SOH| DC1|  ! |  1 |  A |  Q |  a |  q |
| 2 | STX| DC2|  " |  2 |  B |  R |  b |  r |
| 3 | ETX| DC3|  # |  3 |  C |  S |  c |  s |
| 4 | EOT| DC4|  $ |  4 |  D |  T |  d |  t |
| 5 | ENQ| NAK|  % |  5 |  E |  U |  e |  u |
| 6 | ACK| SYN|  & |  6 |  F |  V |  f |  v |
| 7 | BEL| ETB|  ' |  7 |  G |  W |  g |  w |
| 8 | BS | CAN|  ( |  8 |  H |  X |  h |  x |
| 9 | HT | EM |  ) |  9 |  I |  Y |  i |  y |
| A | LF | SUB|  * |  : |  J |  Z |  j |  z |
| B | VT | ESC|  + |  ; |  K |  [ |  k |  { |
| C | FF | FS |  , |  < |  L |  \ |  l |  | |
| D | CR | GS |  - |  = |  M |  ] |  m |  } |
| E | SO | RS |  . |  > |  N |  ^ |  n |  ~ |
| F | SI | US |  / |  ? |  O |  _ |  o | DEL|
+---+----+----+----+----+----+----+----+----+

NUL (null)                      DLE (data link escape)
SOH (start of heading)          DC1 (device control 1)
STX (start of text)             DC2 (device control 2)
ETX (end of text)               DC3 (device control 3)
EOT (end of transmission)       DC4 (device control 4)
ENQ (enquiry)                   NAK (negative acknowledge)
ACK (acknowledge)               SYN (synchronous idle)
BEL (bell)                      ETB (end of trans. block)
BS  (backspace)                 CAN (cancel)
TAB (horizontal tab)            EM  (end of medium)
LF  (line feed, NL new line)    SUB (substitute, EOF end of file)
VT  (vertical tab)              ESC (escape)
FF  (form feed, NP new page)    FS  (file separator)
CR  (carriage return)           GS  (group separator)
SO  (shift out)                 RS  (record separator)
SI  (shift in)                  US  (unit separator)



 

Posted by Scripter
,

Extlib OCaml 에 붙여 쓰는 여러 가지 (써드 파티) 라이브러리 중의 하나이며, OCaml 의 표준 라이브러리가 지원하지 않는 일들(예를 들면 UTF8 문자 지원)을 한다.

현재 최신 버전인 Extlib 1.5.3 은 OCaml 4.00.0 과 4.00.1 용 라이브러리이고, Extlib 1.5.1, 1.5.2 는 OCaml 3.12.0, 3.12.1 용 라이브러리이다

64비트 윈도우의 경우 Extlib 가 전부 설치되지 못하고, 일부(마이트 코드영 라이브러리, 설치 과정 중 1번 선택)만 설치되는 현상이 있다.

설치하는 명령은 (Extlib 의 압축이 해제된 폴더에서)

    Prompt> ocaml install.ml

이다. 설치 과정 중에  모두(3번)를 선택하여 설치가 실패할 경우에는 1번(바이트 코드)를 선택한다. 설치 후 필요한 것은 라이브러리 파일 extLib,cma 이다. 이 라이브러리 파일이 OCaml 3.12.0 과 3.12.1 의 경우에는 %OCAML설치폴더% 에 생성되지만, OCaml 4.00.0 과 4.00.1 의 경우에는  %OCAML설치폴더%\lib\site-lib\extlib 폴더에 생성된다.

Extlib 의 설치가 성공적으로 끝났으면, 다음 간단한 파일을 작성하고 실행해 보자.

 

  * 파일명: helloUTF8.ml (파일 저장 시에 UTF8 인코딩로 저장)

open Printf
open UTF8
(* open UChar *)

let () = Printf.printf "Hello, world!\n"
let () = Printf.printf "안녕하세요?\n"

let str = "안녕하세요?1234"
let () = Printf.printf "length str = %d\n" (length str)
let () = Printf.printf "nth str 5 = %c\n" (UChar.char_of (get str 5))
let () = Printf.printf "nth str 5 = %c\n" (UChar.char_of (get str 6))
let () = Printf.printf "nth str 5 = %c\n" (UChar.char_of (get str 7))
let () = Printf.printf "nth str 5 = %c\n" (UChar.char_of (get str 8))

 

ocaml 이나 ocamlc 를 실행할 때는 항상 환경변수 PATH 와 OCAMLLIB 가 알맞게 맞추어져 있는지 확인한다.  ocaml 의 버전을 확인하는 병령은

Prompt> ocaml -version

이다. (참고로 Extlib 가 설치된 직후에는 이 명령이 먹히지 않으므로 새로운 명령창을 열고, PATH 와 OCAMLLIB 를 다시 설정해 준다.)

Prompt> set PATH=C:\OCaml312\bin;%PATH%

Prompt> set OCAMLLIB=C:\OCaml312\lib

 

* 환경변수 OCAMLLIB 의 설정 확인

Prompt> echo %OCAMLLIB%
C:\OCaml312\lib

 

* OCaml 3.12.1 에 설치된 Extlib 를 사용하는 실행 명령

Prompt> ocaml -I c:\ocaml312 extLib.cma helloUTF8.ml

실행 결과:
Hello, world!
안녕하세요?
length str = 10
nth str 5 = ?
nth str 5 = 1
nth str 5 = 2
nth str 5 = 3

* OCaml 4.00.1 에 설치된 Extlib 를 사용하는 실행 명령

Prompt> ocaml -I c:\ocaml400\lib\site-lib\extlib extLib.cma helloUTF8.ml

 

 * 파일명: testDynArray.ml (동적 배열 모튤 DynArray 을 사용하는 OCaml 소스)

(*
 *  Filename: testDynArray.ml
 *
 *     Purpose: Testing the DynArray module of Extlib.
 *
 *   Execute: ocaml -I C:\OCaml312 extLib.cma testDynArray.ml
 *
 *     Or
 *
 *   Compile: ocaml -I C:\OCaml312 extLib.cma -o testDynArray.exe testDynArray.ml
 *   Execute: testDynArray
 *
 *     Or
 *
 *   Execute: ocaml -I C:\OCaml400\lib\site-lib\exlib extLib.cma testDynArray.ml
 *
 *     Date: 2013. 1. 29.
 *   Author: pkim _AT_ scripts.pe.kr
 *)

open Printf
(* open DynArray *)

let darr = DynArray.create()

let () = DynArray.add darr 5
let () = printf "length of darr = %d\n" (DynArray.length darr)
let () = printf "the first element of darr is %d\n" (DynArray.get darr 0)

let () = DynArray.add darr 7
let () = printf "length of darr = %d\n" (DynArray.length darr)
let () = printf "the last element of darr is %d\n" (DynArray.last darr)

let () = DynArray.iter (printf "%d, ") darr
let () = print_newline()

let () = DynArray.iter (printf "%d, ") (DynArray.map (fun x -> x*x) darr)
let () = print_newline()
let () = print_newline()

let () = DynArray.add darr (-1)
let () = printf "length of darr = %d\n" (DynArray.length darr)
let () = printf "the last element of darr is %d\n" (DynArray.last darr)
let () = DynArray.iter (printf "%d, ") darr
let () = print_newline()

let sumIt arr = DynArray.fold_right (+) arr 0

let () = printf "The summmation of elements of the list is %d\n" (sumIt darr)
let () = print_newline()

let () = printf "Inserting -1 at the second position of the list\n"
let () = DynArray.insert darr 1 (-3)
let () = printf "length of darr = %d\n" (DynArray.length darr)
let () = printf "the last element of darr is %d\n" (DynArray.last darr)
let () = DynArray.iter (printf "%d, ") darr
let () = print_newline()
let () = print_newline()

let () = printf "Deleting the third element of the list\n"
let () = DynArray.delete darr 2
let () = printf "length of darr = %d\n" (DynArray.length darr)
let () = printf "the last element of darr is %d\n" (DynArray.last darr)
let () = DynArray.iter (printf "%d, ") darr
let () = print_newline()
let () = printf "The summmation of absolutes of elements of the list is %d\n" (sumIt (DynArray.map abs darr))
let () = print_newline()

(*
Output:
length of darr = 1
the first element of darr is 5
length of darr = 2
the last element of darr is 7
5, 7,
25, 49,

length of darr = 3
the last element of darr is -1
5, 7, -1,
The summmation of elements of the list is 11

Inserting -1 at the second position of the list
length of darr = 4
the last element of darr is -1
5, -3, 7, -1,

Deleting the third element of the list
length of darr = 3
the last element of darr is -1
5, -3, -1,
The summmation of absolutes of elements of the list is 9
*)

 

 

 

Posted by Scripter
,

컴퓨터 프로그래밍에서 꼭 알아두어야 할 주요 진법은 당연히 10진법, 2진법, 8진법, 16진법이다.
다음은  0 에서 15 까지의 정수를 10진법, 2진법, 8진법, 16진법의 표로 만들어 보여주는 OCaml 소스 코드이다. 진법 변환에 필요한 함수

        int = atoi string radix           (즉, atoi :: string -> int -> int )
        string = itoa number radix    (즉, itoa :: int -> int -> string )

를 OCaml 코드로 자체 작성하여 사용하였다.

(아래의 소스는 Python 소스를 F# 소스로 일대일 변환 수정하고, 또 F# 소스를 OCaml 소스로 바꾼 것이라서 명령형 언어 특징을 위주로 작성되어 있다. 그래서 함수형 언어의 관점으로 보면 사이드 이팩트가 많아 난잡하게 보이는 소스이다.)

  1. (*
  2.  *  Filename: makeRadixTable.ml
  3.  *            Show the radix table with 10-, 2-, 8-, 16-radices.
  4.  *
  5.  *  Execute: ocaml makeRadixTable.ml
  6.  *
  7.  *   Or
  8.  *
  9.  *  Compile: ocamlc -o makeRadixTable.exe makeRadixTable.ml
  10.  *  Execute: makeRadixTable
  11.  *
  12.  *      Date:  2013. 1. 29.
  13.  *    Author:  pkim __AT__scripts.pe.kr
  14.  *)
  15. exception RuntimeError of string
  16. exception ValueError of string
  17. open Printf ;;
  18. let println s = printf "%s\n" s  ;;
  19. let print s =  printf "%s" s  ;;
  20. let printUsage dummy =
  21.     println "Usage: makeRadixTable" ;
  22.     println "Show the radix table with 10-, 2-, 8-, 16-radices."  ;;
  23. let split_char sep str =
  24.   let rec indices acc i =
  25.     try
  26.       let i = succ(String.index_from str i sep) in
  27.       indices (i::acc) i
  28.     with Not_found ->
  29.       (String.length str + 1) :: acc
  30.   in
  31.   let is = indices [0] 0 in
  32.   let rec aux acc = function
  33.     | last::start::tl ->
  34.         let w = String.sub str start (last-start-1) in
  35.         aux (w::acc) (start::tl)
  36.     | _ -> acc
  37.   in
  38.   aux [] is ;;
  39. let sBASE36 = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"  ;;
  40. let rec sdup str n =
  41.         match n with
  42.         | 0 -> ""
  43.         | k when k > 0 -> str ^ (sdup str (n - 1))
  44.         | _ -> ""
  45. let contains s1 s2 =
  46.   try
  47.     let len = String.length s2 in
  48.     for i = 0 to (String.length s1) - len do
  49.       if String.sub s1 i len = s2 then raise Exit
  50.     done;
  51.     false
  52.   with Exit -> true ;;
  53. let join list sep =
  54.     let rec join' list acc =
  55.         match list with
  56.             | [] -> ""
  57.             | [single] -> single
  58.             | one::[two] ->
  59.                         if acc = "" then one ^ sep ^ two
  60.                                     else acc ^ one ^ sep ^ two
  61.             | first::others -> join' others (acc ^ first ^ ", ")
  62.                                         in
  63.                                         join' list "" ;;
  64. let str_reverse str =
        let len = String.length str in
  65.     let res = String.create len in
  66.     for i = 0 to pred len do
  67.         let j = pred len - i in
  68.         res.[i] <- str.[j]
  69.     done;
  70.     res ;;
  71. let itoa num radix =
  72.    let isNegative = ref false in
  73.    let num1 = num + 0 in
  74.    let numx = ref num1 in
  75.    if num < 0 then begin
  76.       isNegative := true ;
  77.       numx := (-num)
  78.    end ;
  79.    let nnumx = !numx in
  80.    let q1 = nnumx in
  81.    let q = ref q1 in
  82.    let r = ref 0 in
  83.    let slen = ref 1 in
  84.    while (!q >= radix) do
  85.        r := !q mod radix ;
  86.        q := !q / radix ;
  87.        slen := !slen + 1
  88.    done ;
  89.    let sslen = !slen in
  90.    let str = String.create sslen in
  91.    let p1 = nnumx in
  92.    let p = ref p1 in
  93.    for i = 0 to sslen - 1 do
  94.        r := !p mod radix ;
  95.        p := !p / radix ;
  96.        str.[i] <- sBASE36.[!r]
  97.    done ;
  98.    let str2 = str_reverse str in
  99.    str2;;
  100. let atoi s radix =
  101.     let ret = ref 0 in
  102.     let isNegative = ref false in
  103.     let len = String.length s in
  104.     let valx = ref 0 in
  105.     let c1 = s.[0] in
  106.     let c = ref c1 in
  107.     if !c = '-' then 
  108.        isNegative := true
  109.     else if (!c >= '0' && !c <= '9') then
  110.         ret := (int_of_char !c) - (int_of_char '0')
  111.     else if (!c >= 'A' && !c <= 'Z') then
  112.         ret := (int_of_char !c) - (int_of_char 'A') + 10
  113.     else if (!c >= 'a' && !c <= 'z') then
  114.         ret := (int_of_char !c) - (int_of_char 'a') + 10 ;
  115.     if (!ret >= radix) then
  116.         raise (ValueError (sprintf "Can not read \"%s\" (as radix %d): '%c' is invalid." s radix !c ) ) ;
  117.     for i = 1 to len - 1 do
  118.         c := s.[i] ;
  119.         ret := (!ret)*radix  ;
  120.         if (!c >= '0' && !c <= '9') then
  121.             valx := int_of_char !c - int_of_char '0' 
  122.         else if (!c >= 'A' && !c <= 'Z') then
  123.             valx := int_of_char !c - int_of_char 'A' + 10
  124.         else if (!c >= 'a' && !c <= 'z') then
  125.             valx := int_of_char !c - int_of_char 'a' + 10 ;
  126.         if (!valx >= radix) then 
                raise (ValueError (sprintf "Can not read \"%s\" (as radix %d): '%c' is invalid." s radix !c ) ) ;
  127.         ret := (!ret) + (!valx)
  128.     done;
  129.     if (!isNegative) then
  130.         ret := (-(!ret) ) ;
  131.     !ret ;;
  132. let makeTable() =
  133.     let sbuf = "" in
  134.     let sbuf = sbuf ^ (sdup "+-------" 4) in
  135.     let sbuf = sbuf ^ "+" in
  136.     println sbuf ;
  137.     let sbuf = "|  Dec" in
  138.     let sbuf = sbuf ^  "\t|   Bin" in
  139.     let sbuf = sbuf ^  "\t|  Oct" in
  140.     let sbuf = sbuf ^  "\t|  Hex  |" in
  141.     println sbuf ;
  142.     let sbuf = ""  in
  143.     let sbuf = sbuf ^ (sdup "+-------" 4) in
  144.     let sbuf = sbuf ^  "+" in
  145.     println sbuf ;
  146.     for i = 0 to (16-1) do
  147.         let sbuf = sprintf "|   %2d" i in
  148.         let abuf = itoa i 2  in
  149.         let tbuf = sprintf "\t|  %4s" abuf   in
  150.         let sbuf = sbuf ^ tbuf   in
  151.         let abuf = itoa i 8    in
  152.         let tbuf = sprintf "\t|   %2s" abuf    in
  153.         let sbuf = sbuf ^ tbuf    in
  154.         let abuf = itoa i 16    in
  155.         let tbuf = sprintf "\t|    %-2s |"  abuf    in
  156.         let sbuf = sbuf ^  tbuf    in
  157.         println sbuf
  158.     done ;
  159.     let sbuf = "" in
  160.     let sbuf = sbuf ^ (sdup  "+-------" 4) in
  161.     let sbuf = sbuf ^  "+" in
  162.     println sbuf ;
  163.     "" ;;
  164. let main() =
  165.     let cmdArgs = Sys.argv in
  166.     if (Array.length cmdArgs > 1 && "-h" = cmdArgs.(1)) then begin
  167.         printUsage() ;
  168.         exit(1)
  169.     end ;
  170.     makeTable() ;;
  171. main()

 


실행 결과:

+-------+-------+-------+-------+ | Dec | Bin | Oct | Hex | +-------+-------+-------+-------+ | 0 | 0 | 0 | 0 | | 1 | 1 | 1 | 1 | | 2 | 10 | 2 | 2 | | 3 | 11 | 3 | 3 | | 4 | 100 | 4 | 4 | | 5 | 101 | 5 | 5 | | 6 | 110 | 6 | 6 | | 7 | 111 | 7 | 7 | | 8 | 1000 | 10 | 8 | | 9 | 1001 | 11 | 9 | | 10 | 1010 | 12 | A | | 11 | 1011 | 13 | B | | 12 | 1100 | 14 | C | | 13 | 1101 | 15 | D | | 14 | 1110 | 16 | E | | 15 | 1111 | 17 | F | +-------+-------+-------+-------+

 

Posted by Scripter
,

다음은  대화형 모드(interactive mode)에서 진법 변환(radix conversion)하는 OCaml 소스 코드이다.

   주: 이 소스는 Python 용으로 만들어 둔 소스를 F# 언어로 바꾸고, 다시 이를 Ocaml
        언어로 바꾸느라 OCaml 언어의 명령형 언어 특징을 위주로 짜여져 있다.

메뉴는 주메뉴 Command: (S)et radix, (A)bout, (Q)uit or E(x)it
와 부메뉴 SubCommand: 'main()' to goto Main menu, 'exit()' or 'quit()' to exit
로 구성되어 있으며, 진법 변환의 핵심은 소스 코드에 자체 작성된 함수 atoi  와  itoa 의 사용이다.

         let value = atoi str srcRdx
         let str = itoa value destRdx

지원되는 진법은 2진법에서 36진법까지이다.

 

  1. (*
  2.  *  Filename: convertRadix.ml
  3.  *            Convert radix in an interactive mode.
  4.  *
  5.  *  Execute: ocaml convertRadix.ml
  6.  *
  7.  *   Or
  8.  *
  9.  *  Compile: ocamlc -o convertRadix.exe convertRadix.ml
  10.  *  Execute: convertRadix
  11.  *
  12.  *      Date:  2013. 1. 28.
  13.  *    Author:  P. Kim   ( pkim _AT_ scripts.pe.kr )
  14.  *)
  15. open Printf;;
  16. exception RuntimeError of string
  17. exception ValueError of string
  18. exception Exit
  19. let println s =
  20.     printf "%s\n" s ;;
  21. let print s =
  22.    printf "%s" s  ;;
  23. let printUsage() =
  24.     println "Usage: convertRadix" ;
  25.     println "Convert radix in a interactive mode, where the maximum radix is 36." ;;
  26. let printAbout() =
  27.     println "    About: Convert radix in a interactive mode."  ;;
  28. let printMainMenu() =
  29.     println "  Command: (S)et radix, (A)bout, (Q)uit or E(x)it"  ;;
  30. let printMainPrompt() =
  31.     print "  Prompt> "  ;;
  32. let printSubMenu srcRadix destRadix =
  33.     println (sprintf "    Convert Radix_%d to Radix_%d\n" srcRadix destRadix )  ;
  34.     println ("    SubCommand: 'main()' to goto Main menu, 'exit()' or 'quit()' to exit" )  ;;
  35. let printSubPrompt() =
  36.     print "    Input Value>> " ;;
  37. let split_char sep str =
  38.   let rec indices acc i =
  39.     try
  40.       let i = succ(String.index_from str i sep) in
  41.       indices (i::acc) i
  42.     with Not_found ->
  43.       (String.length str + 1) :: acc
  44.   in
  45.   let is = indices [0] 0 in
  46.   let rec aux acc = function
  47.     | last::start::tl ->
  48.         let w = String.sub str start (last-start-1) in
  49.         aux (w::acc) (start::tl)
  50.     | _ -> acc
  51.   in
  52.   aux [] is ;;
  53. let sBASE36 = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"  ;;
  54. let contains s1 s2 =
  55.   try
  56.     let len = String.length s2 in
  57.     for i = 0 to (String.length s1) - len do
  58.       if String.sub s1 i len = s2 then raise Exit
  59.     done;
  60.     false
  61.   with Exit -> true ;;
  62. let join list sep =
  63.     let rec join' list acc =
  64.         match list with
  65.             | [] -> ""
  66.             | [single] -> single
  67.             | one::[two] ->
  68.                         if acc = "" then one ^ sep ^ two
  69.                                     else acc ^ one ^ sep ^ two
  70.             | first::others -> join' others (acc ^ first ^ ", ")
  71.                                         in
  72.                                         join' list "" ;;
  73. let str_reverse str =
  74.     let len = String.length str in
  75.     let res = String.create len in
  76.     for i = 0 to pred len do
  77.         let j = pred len - i in
  78.         res.[i] <- str.[j]
  79.     done;
  80.     res ;;
  81. let itoa num radix =
  82.    let isNegative = ref false in
  83.    let num1 = num + 0 in
  84.    let numx = ref num1 in
  85.    if num < 0 then begin
  86.       isNegative := true ;
  87.       numx := (-num)
  88.    end ;
  89.    let nnumx = !numx in
  90.    let q1 = nnumx in
  91.    let q = ref q1 in
  92.    let r = ref 0 in
  93.    let slen = ref 1 in
  94.    while (!q >= radix) do
  95.        r := !q mod radix ;
  96.        q := !q / radix ;
  97.        slen := !slen + 1
  98.    done ;
  99.    let sslen = !slen in
  100.    let str = String.create sslen in
  101.    let p1 = nnumx in
  102.    let p = ref p1 in
  103.    for i = 0 to sslen - 1 do
  104.        r := !p mod radix ;
  105.        p := !p / radix ;
  106.        str.[i] <- sBASE36.[!r]
  107.    done ;
  108.    let str2 = str_reverse str in
  109.    str2;;
  110. let atoi s radix =
  111.     let ret = ref 0 in
  112.     let isNegative = ref false in
  113.     let len = String.length s in
  114.     let valx = ref 0 in
  115.     let c1 = s.[0] in
  116.     let c = ref c1 in
  117.     if !c = '-' then
  118.         isNegative := true
  119.     else if (!c >= '0' && !c <= '9') then
  120.         ret := (int_of_char !c) - (int_of_char '0')
  121.     else if (!c >= 'A' && !c <= 'Z') then
  122.         ret := (int_of_char !c) - (int_of_char 'A') + 10
  123.     else if (!c >= 'a' && !c <= 'z') then
  124.         ret := (int_of_char !c) - (int_of_char 'a') + 10 ;
  125.     if (!ret >= radix) then 
  126.         raise (ValueError (sprintf "Can not read \"%s\" (as radix %d): '%c' is invalid." s radix !c ) ) ;
  127.     for i = 1 to len - 1 do
  128.         c := s.[i] ;
  129.         ret := (!ret)*radix  ;
  130.         if (!c >= '0' && !c <= '9') then
  131.             valx := int_of_char !c - int_of_char '0' 
  132.         else if (!c >= 'A' && !c <= 'Z') then
  133.             valx := int_of_char !c - int_of_char 'A' + 10
  134.         else if (!c >= 'a' && !c <= 'z') then
  135.             valx := int_of_char !c - int_of_char 'a' + 10 ;
  136.         if (!valx >= radix) then 
  137.             raise (ValueError (sprintf "Can not read \"%s\" (as radix %d): '%c' is invalid." s radix !c ) ) ;
  138.         ret := (!ret) + (!valx)
  139.     done;
  140.     if (!isNegative) then
  141.         ret := (-(!ret) ) ;
  142.     !ret ;;
  143. let convertRadix s srcRdx destRdx =
  144.     let valx = (atoi s srcRdx) in
  145.     let ret = (itoa valx destRdx) in
  146.     let ret2 = String.uppercase ret in
  147.     ret2 ;;
  148. let doConvert srcRadix destRadix =
  149.     println "" ;
  150.     printSubMenu srcRadix  destRadix ;
  151.     let stop_flag = ref false in
  152.     try
  153.         while not (!stop_flag) do
  154.             printSubPrompt() ;
  155.             let tt = read_line() in
  156.             let cmd = ref tt in
  157.             while (String.length !cmd) = 0 do
  158.                 let tt2 = read_line() in
  159.                 cmd := tt2
  160.             done;
  161.             if "main()" = !cmd then begin
  162.                 stop_flag := true ;
  163.                 raise ( RuntimeError "" )
  164.             end
  165.             else if "exit()" = !cmd || "quit()" = !cmd then begin
  166.                 exit 0
  167.             end ;
  168.             try 
  169.                 let srcStr = !cmd in
  170.                 let destStr = (convertRadix srcStr srcRadix destRadix) in
  171.                 println (sprintf "        ( %s )_%d   --->   ( %s )_%d" srcStr srcRadix destStr destRadix ) ;
  172.                 println ""
  173.             with ValueError ex -> println (sprintf "    Error caused by: %s\n"  ex)
  174.         done
  175.     with RuntimeError ex -> println (sprintf " %s     "  ex);
  176.     println "" ;;
  177. let doStart() =
  178.     let onlyOnce = ref true in
  179.     try
  180.         while true do
  181.             print "" ;
  182.             if (!onlyOnce) then begin
  183.                 println "  The supported maximum radix is 36." ;
  184.                 onlyOnce := false
  185.             end ;
  186.             printMainMenu() ;
  187.             printMainPrompt() ;
  188.             let tcmds = read_line() in
  189.             let cmds = ref tcmds in
  190.             while (String.length !cmds) = 0 do
  191.                 let tt = read_line() in
  192.                 cmds := tt
  193.             done;
  194.             let cmd = !cmds.[0] in
  195.             if (contains  "qQxX" (sprintf "%c" cmd)) && (String.length !cmds) = 1 then begin
  196.                 exit 0
  197.             end
  198.             else if (contains  "aA" (sprintf "%c" cmd)) && (String.length !cmds) = 1 then begin
  199.                 printAbout()
  200.             end
  201.             else if (contains  "sS" (sprintf "%c" cmd)) && (String.length !cmds) = 1 then begin
  202.                 print "  Input the source and target radices (say, 16 2): "  ;
  203.                 let tt = read_line() in
  204.                 let line = ref tt in
  205.                 let ta = (split_char ' ' !line) in
  206.                 let st = ref ta in
  207.                 while (List.length !st) < 2 do
  208.                     print "  Input the source and target radices (say, 16 2): "  ;
  209.                     let tt2 = read_line() in
  210.                     let ta2 = (split_char ' ' tt2) in
  211.                     st := ta2
  212.                 done;
  213.                 let st2 = Array.of_list !st in
  214.                 let srcRadix = int_of_string (st2.(0)) in
  215.                 let destRadix = int_of_string (st2.(1)) in
  216.                 doConvert srcRadix destRadix
  217.             end ;
  218.             print ""
  219.        done 
  220.     with RuntimeError ex -> println (sprintf "%s Error found!!" ex);;
  221. (* Begin here *)
  222. let main() =
  223.     let cmdArgs = Sys.argv in
  224.     if (Array.length cmdArgs > 1) && ("-h" = cmdArgs.(1)) then begin
  225.         printUsage() ;
  226.         exit 1
  227.     end
  228.     else begin
  229.         doStart()
  230.     end ;;
  231. main();;



컴파일> ocamlc -o convertRadix.exe convertRadix.fs

실행> convertRadix

  The supported maximum radix is 36.
  Command: (S)et radix, (A)bout, (Q)uit or E(x)it
  Prompt> s
  Input the source and target radices (say, 16 2): 10 8

    Convert Radix_10 to Radix_8

    SubCommand: 'main()' to goto Main menu, 'exit()' or 'quit()' to exit
    Input Value>> 200
        ( 200 )_10   --->   ( 310 )_8

    Input Value>> main()


  Command: (S)et radix, (A)bout, (Q)uit or E(x)it
  Prompt> S
  Input the source and target radices (say, 16 2): 8 10

    Convert Radix_8 to Radix_10

    SubCommand: 'main()' to goto Main menu, 'exit()' or 'quit()' to exit
    Input Value>> 2666
        ( 2666 )_8   --->   ( 1462 )_10

    Input Value>> main()


  Command: (S)et radix, (A)bout, (Q)uit or E(x)it
  Prompt> x


Posted by Scripter
,

다음은  이차방정식 x^2 - x - 1  = 0 의 양의 근 즉 황금비율(golden ratio)을 구하는 OCaml 소스이다. 황금비율을 구하는 비례방정식은   1 : x = x : (x+1) 이며, 이를 이차방정식으로 표현한 것이 x^2 - x - 1  = 0 이다.

See:  http://en.wikipedia.org/wiki/Golden_ratio


  1. (*
  2.  *  Filename: testGoldenRatio.ml
  3.  *    황금률(즉, 이차방정식 x^2 - x - 1  = 0 의 양의 근)을 계산한다.
  4.  *
  5.  *   Execute: ocaml testGoldenRatio.ml
  6.  *
  7.  *   Compile: ocamlc -o testGoldenRatio.exe testGoldenRatio.ml
  8.  *   Execute: testGoldenRatio
  9.  *
  10.  *      Date:  2013/01/27
  11.  *    Author: P. Kim   [ pkim _AT_ scripts.pe.kr ]
  12.  *)
  13. open Printf;;
  14. let printUsing() =
  15.     printf "Using: TestGoldenRatio [-h|-help]\n" ;
  16.     printf "This calculates the value of the golden ratio.\n" ;;
  17. exception ZeroCoefficientException;;
  18. exception NegativeDiscriminantException;;
  19. (* 이차방정식 a x^2 + b x + c  = 0 의 근을 구한다. *)
  20. let findQuadraticRoot a b c =
  21.     if a = 0.0 then begin
  22.         raise ZeroCoefficientException
  23.     end
  24.     else if (b*.b -. 4.0*.a*.c < 0.0) then begin
  25.         raise NegativeDiscriminantException
  26.     end;
  27.     let x1 = ((-.b) +. (sqrt (b*.b -. 4.0*.a*.c))) /. (2.0 *. a) in
  28.     let x2 = ((-.b) -. (sqrt (b*.b -. 4.0*.a*.c))) /. (2.0 *. a) in
  29.     x1, x2  ;;  (* 리턴 겂 두 개 *)
  30. (* 실행 시작 지점 *)
  31. let cmdArgs = Sys.argv;;
  32. if (Array.length cmdArgs > 1) && (cmdArgs.(1) = "-h" || cmdArgs.(1) = "-help") then
  33. begin
  34.     printUsing();
  35.     exit 1
  36. end ;;
  37. let x1, x2  = findQuadraticRoot 1.0  (-1.0)  (-1.0) ;;
  38. if x1 >= x2 then begin
  39.     printf "The bigger root is %g " x1 ;
  40.     printf "and the less root is %g.\n" x2
  41. end
  42. else begin
  43.     printf "The bigger root is %g, " x2 ;
  44.     printf "and the less root is %g.\n" x1
  45. end ;;

 

컴파일> ocamlc -o testGoldenRatio.exe testGoldenRatio.ml

실행> testGoldenRatio
The bigger root is 1.61803 and the less root is -0.618034.



Posted by Scripter
,

현재 시각을 컨솔에 보여주는 간단한 OCaml 언어 소스 코드이다.
UTC란 1970년 1월 1일 0시 0분 0초를 기준으로 하여 경과된 초 단위의 총 시간을 의미한다.
UTC(Universal Time  Coordinated, 협정세계시, 協定世界時)

 

  1. (*
  2.  *  Filename: testCTimeApp.ml
  3.  *
  4.  *  Execute: Uncomment the line (* #load "unix.cma" ;; *)
  5.  *           ocaml testCTimeApp.ml
  6.  *
  7.  *  Compile: ocamlc -g -c testCTimeApp.ml
  8.  *           ocamlc -o testCTimeApp.exe unix.cma testCTimeApp.cmo
  9.  *  Execute: testCTimeApp 
  10.  *)
  11. (* #load "unix.cma" ;; *)    (* ocaml 로 실행 시에는 이 곳의 주석 표시 제거 *)
  12. open Unix ;;
  13. open Printf;;
  14. let weekNames = [| "일"; "월"; "화"; "수"; "목"; "금"; "토" |]
  15. let now = Unix.time ()
  16. let {Unix.tm_sec=seconds; tm_min=minutes; tm_hour=hours;
  17.      tm_mday=day_of_month; tm_mon=month; tm_year=year;
  18.      tm_wday=wday; tm_yday=yday; tm_isdst=isdst} =
  19.   Unix.localtime now
  20. let startOfEpoch = mktime (localtime (time ())) ;;
  21. (* 1970년 1월 1일 0시 0분 0초부터 시작하여 현재까지의 초 *)
  22. let () = printf "UTC: %.0f\n" (fst startOfEpoch)
  23. (* 현재 시각 표시: 20xx년 xx월 xx일 (x요일) xx시 xx분 xx초 *)
  24. let () = printf "%d년 " (1970 + year)
  25. let () = printf "%d월 " (1 + month)     (* Not 1 + now.Month !! *)
  26. let () = printf "%d일 " (day_of_month)
  27. let () = printf "(%s요일) " (weekNames.(wday))
  28. let () = printf "%d시 " (hours)
  29. let () = printf "%d분 " (minutes)
  30. let () = printf "%d초" (seconds)
  31. let () = print_newline()
  32. (* 1월 1일은 1, 1월 2일은 2 *)
  33. let () = printf "올해 몇 번째 날: %d, " (yday)
  34. (* true 이면 서머타임 있음 *)
  35. let str = if not (isdst) then "안함" else "함"
  36. let () = printf "서머타임 적용 여부: %s\n"  str



컴파일> ocamlc -o testCTimeApp.exe testCTimeApp.ml

실행> testCTimeApp
UTC: 1359278723
2083년 1월 27일 (일요일) 18시 25분 23초
올해 몇 번째 날: 26, 서머타임 적용 여부: 안함



Posted by Scripter
,

F# 용 소스파일 testForFor.fs 를 OCaml 용으로 수정한 것이다.
F# 언어는 if 구문, for 구문, 들여쓰기 규칙이 Python의 것과 닮았지만, OCam 언어는 (C 언어 처럼) 들여쓰기 규칙이 없다. 그 대신 구문의 끝을 한 개의 세미콜론(;)으로 끝낼지, 두 개의 세미콜론(;;)으로 끝낼지, 아니면 세미콜론을 안 붙일 것이지를 정확하게 지켜야 한다. OCam 언어는 let 으로 시작하는 구문에 세미콜론 없이 예약어 in 으로 (정의가) 계속 이어지는 구문도 많이 쓰인다.

두 개의 세미콜론(;;) 으로 끝나는 곳이 정의가 완전히 끝난 곳임을 알리는 구문이고, 한 개의 세미 콜론으로 끝나는 곳은 정의가 아직 완성 도지 않았으니 무시하라는 구문이다.

 

아래는 ocaml 을 실행시켜서서 (대화영 모드에서) 예약어 in 의 역할을 테스트한 내용이다.

# let z = 2;;
val z : int = 2
# let x = [ 1; 2; 3 ];;
val x : int list = [1; 2; 3]
# let a = let x = 5 in let y = 7 in let z = x + y in 9 + x + y + z;;
val a : int = 33
# a;;
- : int = 33
# x;;
- : int list = [1; 2; 3]
# z;;
- : int = 2
# let a = let x = 5 in let y = 7 in let t = x + y in 9 + x + y + t;;
val a : int = 33
# a;;
- : int = 33
# z;;
- : int = 2
# t;;
Characters 0-1:
  t;;
  ^
Error: Unbound value t

 

OCaml 언어는 (F# 언어 처럼) 함수형 언어기도 하고 명령형 언어이기도 하므로, 여기서는 가급적 OCaml 의 명령형 언어의 특징을 위주로 작성하였다.

  1. (* 
  2.  *  Filename: testForFor.ml
  3.  *
  4.  *         이겹 for 반복문을 사용하여 19단표를 컨솔에 출력한다.
  5.  *
  6.  *   Execute: ocaml testForFor.ml
  7.  *
  8.  *    Or
  9.  *
  10.  *   Compile: ocamlc -o testForFor.exe testForFor.ml
  11.  *   Execute: testForFor
  12.  *
  13.  *  Date:  2013. 1. 27.
  14.  *)
  15. let getDan dan = 
  16.     let t = Array.make 19 "" in
  17.     for j = 0 to (19 - 1) do
  18.         let sa = Printf.sprintf "%2d" dan in
  19.         let sb = Printf.sprintf "%2d" (j + 1) in
  20.         let sval = Printf.sprintf "%3d" (dan*(j + 1)) in
  21.         t.(j) <- Printf.sprintf ("%s x %s = %s") sa sb sval
  22.     done;
  23.     t;;  (* 리턴 값.  함수의 정의가 여기서 완전히 끝나므로 두 개의 세미콜론 *)
  24. (* 19단표를 모두 80컬럼 컨솔에 출력한다. *)
  25. let printAllNineteenDan() =    (* OCaml 소스 코드에서는 (F# 소스 코드에서 처럼) 리스트 대신 배열을 사용한다. *)
  26.     let arr = Array.make_matrix 18 19 "aa" in
  27.     for i = 2 to (20 - 1) do
  28.         arr.(i - 2) <- (getDan i );
  29.     done;
  30.     let d = [| 2; 7; 11; 16 |] in       (* 각 줄단위 블럭의 첫단 *)
  31.     let counter = [| 5; 4; 5; 4 |] in         (* 각 줄단위 블럭에 속한 단의 개수 *)
  32.     let lines = Array.make 19 "" in
  33.     for k = 0 to ((Array.length d) - 1) do
  34.         (* 8-바이트 길이의 한 줄씩 완성 *)
  35.         for i = 0 to (19 - 1) do
  36.             lines.(i) <- (arr.(d.(k)-2).(i));
  37.             for j = 1 to (counter.(k) - 1) do
  38.                 lines.(i) <- Printf.sprintf ("%s   %s") lines.(i) arr.(d.(k)-2+j).(i)
  39.             done;
  40.         done;
  41.         (* 80 바이트 길이의 한 줄씩 출력 *)
  42.         for i = 0 to (19 - 1) do
  43.             Printf.printf "%s\n" (lines.(i))
  44.         done;
  45.         Printf.printf "\n";
  46.     done;;
  47. printAllNineteenDan();;


컴파일: 
Prompt> ocamlc -o testForFor.exe testForFor.ml 

실행: 
Prompt> testForFor 
 2 x  1 =   2    3 x  1 =   3    4 x  1 =   4    5 x  1 =   5    6 x  1 =   6
 2 x  2 =   4    3 x  2 =   6    4 x  2 =   8    5 x  2 =  10    6 x  2 =  12
 2 x  3 =   6    3 x  3 =   9    4 x  3 =  12    5 x  3 =  15    6 x  3 =  18
 2 x  4 =   8    3 x  4 =  12    4 x  4 =  16    5 x  4 =  20    6 x  4 =  24
 2 x  5 =  10    3 x  5 =  15    4 x  5 =  20    5 x  5 =  25    6 x  5 =  30
 2 x  6 =  12    3 x  6 =  18    4 x  6 =  24    5 x  6 =  30    6 x  6 =  36
 2 x  7 =  14    3 x  7 =  21    4 x  7 =  28    5 x  7 =  35    6 x  7 =  42
 2 x  8 =  16    3 x  8 =  24    4 x  8 =  32    5 x  8 =  40    6 x  8 =  48
 2 x  9 =  18    3 x  9 =  27    4 x  9 =  36    5 x  9 =  45    6 x  9 =  54
 2 x 10 =  20    3 x 10 =  30    4 x 10 =  40    5 x 10 =  50    6 x 10 =  60
 2 x 11 =  22    3 x 11 =  33    4 x 11 =  44    5 x 11 =  55    6 x 11 =  66
 2 x 12 =  24    3 x 12 =  36    4 x 12 =  48    5 x 12 =  60    6 x 12 =  72
 2 x 13 =  26    3 x 13 =  39    4 x 13 =  52    5 x 13 =  65    6 x 13 =  78
 2 x 14 =  28    3 x 14 =  42    4 x 14 =  56    5 x 14 =  70    6 x 14 =  84
 2 x 15 =  30    3 x 15 =  45    4 x 15 =  60    5 x 15 =  75    6 x 15 =  90
 2 x 16 =  32    3 x 16 =  48    4 x 16 =  64    5 x 16 =  80    6 x 16 =  96
 2 x 17 =  34    3 x 17 =  51    4 x 17 =  68    5 x 17 =  85    6 x 17 = 102
 2 x 18 =  36    3 x 18 =  54    4 x 18 =  72    5 x 18 =  90    6 x 18 = 108
 2 x 19 =  38    3 x 19 =  57    4 x 19 =  76    5 x 19 =  95    6 x 19 = 114

 7 x  1 =   7    8 x  1 =   8    9 x  1 =   9   10 x  1 =  10
 7 x  2 =  14    8 x  2 =  16    9 x  2 =  18   10 x  2 =  20
 7 x  3 =  21    8 x  3 =  24    9 x  3 =  27   10 x  3 =  30
 7 x  4 =  28    8 x  4 =  32    9 x  4 =  36   10 x  4 =  40
 7 x  5 =  35    8 x  5 =  40    9 x  5 =  45   10 x  5 =  50
 7 x  6 =  42    8 x  6 =  48    9 x  6 =  54   10 x  6 =  60
 7 x  7 =  49    8 x  7 =  56    9 x  7 =  63   10 x  7 =  70
 7 x  8 =  56    8 x  8 =  64    9 x  8 =  72   10 x  8 =  80
 7 x  9 =  63    8 x  9 =  72    9 x  9 =  81   10 x  9 =  90
 7 x 10 =  70    8 x 10 =  80    9 x 10 =  90   10 x 10 = 100
 7 x 11 =  77    8 x 11 =  88    9 x 11 =  99   10 x 11 = 110
 7 x 12 =  84    8 x 12 =  96    9 x 12 = 108   10 x 12 = 120
 7 x 13 =  91    8 x 13 = 104    9 x 13 = 117   10 x 13 = 130
 7 x 14 =  98    8 x 14 = 112    9 x 14 = 126   10 x 14 = 140
 7 x 15 = 105    8 x 15 = 120    9 x 15 = 135   10 x 15 = 150
 7 x 16 = 112    8 x 16 = 128    9 x 16 = 144   10 x 16 = 160
 7 x 17 = 119    8 x 17 = 136    9 x 17 = 153   10 x 17 = 170
 7 x 18 = 126    8 x 18 = 144    9 x 18 = 162   10 x 18 = 180
 7 x 19 = 133    8 x 19 = 152    9 x 19 = 171   10 x 19 = 190

11 x  1 =  11   12 x  1 =  12   13 x  1 =  13   14 x  1 =  14   15 x  1 =  15
11 x  2 =  22   12 x  2 =  24   13 x  2 =  26   14 x  2 =  28   15 x  2 =  30
11 x  3 =  33   12 x  3 =  36   13 x  3 =  39   14 x  3 =  42   15 x  3 =  45
11 x  4 =  44   12 x  4 =  48   13 x  4 =  52   14 x  4 =  56   15 x  4 =  60
11 x  5 =  55   12 x  5 =  60   13 x  5 =  65   14 x  5 =  70   15 x  5 =  75
11 x  6 =  66   12 x  6 =  72   13 x  6 =  78   14 x  6 =  84   15 x  6 =  90
11 x  7 =  77   12 x  7 =  84   13 x  7 =  91   14 x  7 =  98   15 x  7 = 105
11 x  8 =  88   12 x  8 =  96   13 x  8 = 104   14 x  8 = 112   15 x  8 = 120
11 x  9 =  99   12 x  9 = 108   13 x  9 = 117   14 x  9 = 126   15 x  9 = 135
11 x 10 = 110   12 x 10 = 120   13 x 10 = 130   14 x 10 = 140   15 x 10 = 150
11 x 11 = 121   12 x 11 = 132   13 x 11 = 143   14 x 11 = 154   15 x 11 = 165
11 x 12 = 132   12 x 12 = 144   13 x 12 = 156   14 x 12 = 168   15 x 12 = 180
11 x 13 = 143   12 x 13 = 156   13 x 13 = 169   14 x 13 = 182   15 x 13 = 195
11 x 14 = 154   12 x 14 = 168   13 x 14 = 182   14 x 14 = 196   15 x 14 = 210
11 x 15 = 165   12 x 15 = 180   13 x 15 = 195   14 x 15 = 210   15 x 15 = 225
11 x 16 = 176   12 x 16 = 192   13 x 16 = 208   14 x 16 = 224   15 x 16 = 240
11 x 17 = 187   12 x 17 = 204   13 x 17 = 221   14 x 17 = 238   15 x 17 = 255
11 x 18 = 198   12 x 18 = 216   13 x 18 = 234   14 x 18 = 252   15 x 18 = 270
11 x 19 = 209   12 x 19 = 228   13 x 19 = 247   14 x 19 = 266   15 x 19 = 285

16 x  1 =  16   17 x  1 =  17   18 x  1 =  18   19 x  1 =  19
16 x  2 =  32   17 x  2 =  34   18 x  2 =  36   19 x  2 =  38
16 x  3 =  48   17 x  3 =  51   18 x  3 =  54   19 x  3 =  57
16 x  4 =  64   17 x  4 =  68   18 x  4 =  72   19 x  4 =  76
16 x  5 =  80   17 x  5 =  85   18 x  5 =  90   19 x  5 =  95
16 x  6 =  96   17 x  6 = 102   18 x  6 = 108   19 x  6 = 114
16 x  7 = 112   17 x  7 = 119   18 x  7 = 126   19 x  7 = 133
16 x  8 = 128   17 x  8 = 136   18 x  8 = 144   19 x  8 = 152
16 x  9 = 144   17 x  9 = 153   18 x  9 = 162   19 x  9 = 171
16 x 10 = 160   17 x 10 = 170   18 x 10 = 180   19 x 10 = 190
16 x 11 = 176   17 x 11 = 187   18 x 11 = 198   19 x 11 = 209
16 x 12 = 192   17 x 12 = 204   18 x 12 = 216   19 x 12 = 228
16 x 13 = 208   17 x 13 = 221   18 x 13 = 234   19 x 13 = 247
16 x 14 = 224   17 x 14 = 238   18 x 14 = 252   19 x 14 = 266
16 x 15 = 240   17 x 15 = 255   18 x 15 = 270   19 x 15 = 285
16 x 16 = 256   17 x 16 = 272   18 x 16 = 288   19 x 16 = 304
16 x 17 = 272   17 x 17 = 289   18 x 17 = 306   19 x 17 = 323
16 x 18 = 288   17 x 18 = 306   18 x 18 = 324   19 x 18 = 342
16 x 19 = 304   17 x 19 = 323   18 x 19 = 342   19 x 19 = 361



 

Posted by Scripter
,

소스 파일명: TestNoWhile.ml

  1. (*
  2.  *  Filename: testNoWhile.ml
  3.  *
  4.  *  Purpose:  Example not using the while loop syntax 
  5.  *                while ....
  6.  * 
  7.  *  Execute: ocaml testNoWhile.ml -200 300
  8.  * 
  9.  *    Or
  10.  * 
  11.  *  Compile: ocamlc -o testNoWhile.exe testNoWhile.ml
  12.  *  Execute: testNoWhile -200 300
  13.  *)
  14. (* 사용법 표시 *)
  15. let printUsage() =
  16.     Printf.printf "Using: testNoWhile.py [integer1] [integer2]\n";
  17.     Printf.printf "This finds the greatest common divisor of the given two integers.\n";;
  18. let cmdArgs = Sys.argv;; 
  19. if not ((Array.length cmdArgs) == 3) then
  20.     printUsage();
  21. if not ((Array.length cmdArgs) == 3) then
  22.     exit 1;;
  23. (*
  24. // --------------------------------------
  25. // 명령행 인자의 두 스트링을 가져와서
  26. // 정수 타입으로 변환하여
  27. // 변수 val1과 val2에 저장한다.
  28. *)
  29. let val1 = int_of_string cmdArgs.(1);;
  30. let val2 = int_of_string cmdArgs.(2);;
  31. let a = ref (abs val1);;
  32. let b = ref (abs val2);;
  33. let max x y = if y > x then y else x;;
  34. let min x y = if y > x then x else y;;
  35. let maxab = max !a !b;;
  36. let minab = min !a !b;;
  37. (* a는 |val1|, |val2| 중 큰 값 *)
  38. a := maxab;;
  39. b := minab;;
  40. (*
  41. // --------------------------------------
  42. // 재귀호출 Euclidean 알고리즘
  43. //
  44. //     Euclidean 알고리즘의 반복 (나머지가 0이 될 때 까지)
  45. //     나머지가 0이면 그 때 나눈 수(제수) x가 최대공약수(GCD)이다.
  46.  *)
  47. let rec gcdRecursive x y =
  48.     match y with
  49.     | 0 -> x
  50.     | _ -> gcdRecursive y (x mod y);;
  51. let gcd = gcdRecursive !a !b;;
  52. (* 최대공약수(GCD)를 출력한다. *)
  53. Printf.printf "GCD(%d, %d) = %d\n" val1 val2 gcd;
  54. exit 0;;

 

컴파일:
Command> ocamlc -o testNoWhile.exe testNoWhile.fs

실행:
Command> testNoWhile
Using: testNoWhile [integer1] [integer2]
This finds the greatest common divisor of the given two integers.

Command> testNoWhile -200 300
GCD(-200, 300) = 100

Command> testNoWhile -200 0
GCD(-200, 0) = 200

Command> testNoWhile 125 100
GCD(125, 100) = 25

Command> testNoWhile 23 25
GCD(23, 25) = 1



Posted by Scripter
,