src/HOL/Matrix/ExactFloatingPoint.ML
changeset 15178 5f621aa35c25
equal deleted inserted replaced
15177:e7616269fdca 15178:5f621aa35c25
       
     1 structure ExactFloatingPoint :
       
     2 sig
       
     3     exception Destruct_floatstr of string
       
     4 				   
       
     5     val destruct_floatstr : (char -> bool) -> (char -> bool) -> string -> bool * string * string * bool * string
       
     6 									  
       
     7     exception Floating_point of string
       
     8 				
       
     9     type floatrep = IntInf.int * IntInf.int
       
    10     val approx_dec_by_bin : IntInf.int -> floatrep -> floatrep * floatrep
       
    11     val approx_decstr_by_bin : int -> string -> floatrep * floatrep
       
    12 end 
       
    13 =
       
    14 struct
       
    15 
       
    16 fun fst (a,b) = a
       
    17 fun snd (a,b) = b
       
    18 
       
    19 val filter = List.filter;
       
    20 
       
    21 exception Destruct_floatstr of string;
       
    22 
       
    23 fun destruct_floatstr isDigit isExp number = 
       
    24     let
       
    25 	val numlist = filter (not o Char.isSpace) (String.explode number)
       
    26 	
       
    27 	fun countsigns ((#"+")::cs) = countsigns cs
       
    28 	  | countsigns ((#"-")::cs) = 
       
    29 	    let	
       
    30 		val (positive, rest) = countsigns cs 
       
    31 	    in
       
    32 		(not positive, rest)
       
    33 	    end
       
    34 	  | countsigns cs = (true, cs)
       
    35 
       
    36 	fun readdigits [] = ([], [])
       
    37 	  | readdigits (q as c::cs) = 
       
    38 	    if (isDigit c) then 
       
    39 		let
       
    40 		    val (digits, rest) = readdigits cs
       
    41 		in
       
    42 		    (c::digits, rest)
       
    43 		end
       
    44 	    else
       
    45 		([], q)		
       
    46 
       
    47 	fun readfromexp_helper cs =
       
    48 	    let
       
    49 		val (positive, rest) = countsigns cs
       
    50 		val (digits, rest') = readdigits rest
       
    51 	    in
       
    52 		case rest' of
       
    53 		    [] => (positive, digits)
       
    54 		  | _ => raise (Destruct_floatstr number)
       
    55 	    end	    
       
    56 
       
    57 	fun readfromexp [] = (true, [])
       
    58 	  | readfromexp (c::cs) = 
       
    59 	    if isExp c then
       
    60 		readfromexp_helper cs
       
    61 	    else 
       
    62 		raise (Destruct_floatstr number)		
       
    63 
       
    64 	fun readfromdot [] = ([], readfromexp [])
       
    65 	  | readfromdot ((#".")::cs) = 
       
    66 	    let		
       
    67 		val (digits, rest) = readdigits cs
       
    68 		val exp = readfromexp rest
       
    69 	    in
       
    70 		(digits, exp)
       
    71 	    end		
       
    72 	  | readfromdot cs = readfromdot ((#".")::cs)
       
    73 			    
       
    74 	val (positive, numlist) = countsigns numlist				 
       
    75 	val (digits1, numlist) = readdigits numlist				 
       
    76  	val (digits2, exp) = readfromdot numlist
       
    77     in
       
    78 	(positive, String.implode digits1, String.implode digits2, fst exp, String.implode (snd exp))
       
    79     end
       
    80 
       
    81 type floatrep = IntInf.int * IntInf.int
       
    82 
       
    83 exception Floating_point of string;
       
    84 
       
    85 val ln2_10 = (Math.ln 10.0)/(Math.ln 2.0)
       
    86 	
       
    87 fun intmul a b = IntInf.* (a,b)
       
    88 fun intsub a b = IntInf.- (a,b)	
       
    89 fun intadd a b = IntInf.+ (a,b) 		 
       
    90 fun intpow a b = IntInf.pow (a, IntInf.toInt b);
       
    91 fun intle a b = IntInf.<= (a, b);
       
    92 fun intless a b = IntInf.< (a, b);
       
    93 fun intneg a = IntInf.~ a;
       
    94 val zero = IntInf.fromInt 0;
       
    95 val one = IntInf.fromInt 1;
       
    96 val two = IntInf.fromInt 2;
       
    97 val ten = IntInf.fromInt 10;
       
    98 val five = IntInf.fromInt 5;
       
    99 
       
   100 fun find_most_significant q r = 
       
   101     let 
       
   102 	fun int2real i = 
       
   103 	    case Real.fromString (IntInf.toString i) of 
       
   104 		SOME r => r 
       
   105 	      | NONE => raise (Floating_point "int2real")	
       
   106 	fun subtract (q, r) (q', r') = 
       
   107 	    if intle r r' then
       
   108 		(intsub q (intmul q' (intpow ten (intsub r' r))), r)
       
   109 	    else
       
   110 		(intsub (intmul q (intpow ten (intsub r r'))) q', r')
       
   111 	fun bin2dec d =
       
   112 	    if intle zero d then 
       
   113 		(intpow two d, zero)
       
   114 	    else
       
   115 		(intpow five (intneg d), d)				
       
   116 		
       
   117 	val L = IntInf.fromInt (Real.floor (int2real (IntInf.fromInt (IntInf.log2 q)) + (int2real r) * ln2_10))	
       
   118 	val L1 = intadd L one
       
   119 
       
   120 	val (q1, r1) = subtract (q, r) (bin2dec L1) 		
       
   121     in
       
   122 	if intle zero q1 then 
       
   123 	    let
       
   124 		val (q2, r2) = subtract (q, r) (bin2dec (intadd L1 one))
       
   125 	    in
       
   126 		if intle zero q2 then 
       
   127 		    raise (Floating_point "find_most_significant")
       
   128 		else
       
   129 		    (L1, (q1, r1))
       
   130 	    end
       
   131 	else
       
   132 	    let
       
   133 		val (q0, r0) = subtract (q, r) (bin2dec L)
       
   134 	    in
       
   135 		if intle zero q0 then
       
   136 		    (L, (q0, r0))
       
   137 		else
       
   138 		    raise (Floating_point "find_most_significant")
       
   139 	    end		    
       
   140     end
       
   141 
       
   142 fun approx_dec_by_bin n (q,r) =
       
   143     let	
       
   144 	fun addseq acc d' [] = acc
       
   145 	  | addseq acc d' (d::ds) = addseq (intadd acc (intpow two (intsub d d'))) d' ds
       
   146 
       
   147 	fun seq2bin [] = (zero, zero)
       
   148 	  | seq2bin (d::ds) = (intadd (addseq zero d ds) one, d)
       
   149 
       
   150 	fun approx d_seq d0 precision (q,r) = 
       
   151 	    if q = zero then 
       
   152 		let val x = seq2bin d_seq in
       
   153 		    (x, x)
       
   154 		end
       
   155 	    else    
       
   156 		let 
       
   157 		    val (d, (q', r')) = find_most_significant q r
       
   158 		in	
       
   159 		    if intless precision (intsub d0 d) then 
       
   160 			let 
       
   161 			    val d' = intsub d0 precision
       
   162 			    val x1 = seq2bin (d_seq)
       
   163 			    val x2 = (intadd (intmul (fst x1) (intpow two (intsub (snd x1) d'))) one,  d') (* = seq2bin (d'::d_seq) *) 
       
   164 			in
       
   165 			    (x1, x2)
       
   166 			end
       
   167 		    else
       
   168 			approx (d::d_seq) d0 precision (q', r') 						    		
       
   169 		end		
       
   170 	
       
   171 	fun approx_start precision (q, r) =
       
   172 	    if q = zero then 
       
   173 		((zero, zero), (zero, zero))
       
   174 	    else
       
   175 		let 
       
   176 		    val (d, (q', r')) = find_most_significant q r
       
   177 		in	
       
   178 		    if intle precision zero then 
       
   179 			let
       
   180 			    val x1 = seq2bin [d]
       
   181 			in
       
   182 			    if q' = zero then 
       
   183 				(x1, x1)
       
   184 			    else
       
   185 				(x1, seq2bin [intadd d one])
       
   186 			end
       
   187 		    else
       
   188 			approx [d] d precision (q', r')
       
   189 		end		
       
   190     in
       
   191 	if intle zero q then 
       
   192 	    approx_start n (q,r)
       
   193 	else
       
   194 	    let 
       
   195 		val ((a1,b1), (a2, b2)) = approx_start n (intneg q, r) 
       
   196 	    in
       
   197 		((intneg a2, b2), (intneg a1, b1))
       
   198 	    end					
       
   199     end
       
   200 
       
   201 fun approx_decstr_by_bin n decstr =
       
   202     let 
       
   203 	fun str2int s = case IntInf.fromString s of SOME x => x | NONE => zero 
       
   204 	fun signint p x = if p then x else intneg x
       
   205 
       
   206 	val (p, d1, d2, ep, e) = destruct_floatstr Char.isDigit (fn e => e = #"e" orelse e = #"E") decstr
       
   207 	val s = IntInf.fromInt (size d2)
       
   208 		
       
   209 	val q = signint p (intadd (intmul (str2int d1) (intpow ten s)) (str2int d2))
       
   210 	val r = intsub (signint ep (str2int e)) s
       
   211     in
       
   212 	approx_dec_by_bin (IntInf.fromInt n) (q,r)
       
   213     end
       
   214 
       
   215 end;