cannam@127: (* cannam@127: * Copyright (c) 1997-1999 Massachusetts Institute of Technology cannam@127: * Copyright (c) 2003, 2007-14 Matteo Frigo cannam@127: * Copyright (c) 2003, 2007-14 Massachusetts Institute of Technology cannam@127: * cannam@127: * This program is free software; you can redistribute it and/or modify cannam@127: * it under the terms of the GNU General Public License as published by cannam@127: * the Free Software Foundation; either version 2 of the License, or cannam@127: * (at your option) any later version. cannam@127: * cannam@127: * This program is distributed in the hope that it will be useful, cannam@127: * but WITHOUT ANY WARRANTY; without even the implied warranty of cannam@127: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the cannam@127: * GNU General Public License for more details. cannam@127: * cannam@127: * You should have received a copy of the GNU General Public License cannam@127: * along with this program; if not, write to the Free Software cannam@127: * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA cannam@127: * cannam@127: *) cannam@127: cannam@127: (* The generator keeps track of numeric constants in symbolic cannam@127: expressions using the abstract number type, defined in this file. cannam@127: cannam@127: Our implementation of the number type uses arbitrary-precision cannam@127: arithmetic from the built-in Num package in order to maintain an cannam@127: accurate representation of constants. This allows us to output cannam@127: constants with many decimal places in the generated C code, cannam@127: ensuring that we will take advantage of the full precision cannam@127: available on current and future machines. cannam@127: cannam@127: Note that we have to write our own routine to compute roots of cannam@127: unity, since the Num package only supplies simple arithmetic. The cannam@127: arbitrary-precision operations in Num look like the normal cannam@127: operations except that they have an appended slash (e.g. +/ -/ */ cannam@127: // etcetera). *) cannam@127: cannam@127: open Num cannam@127: cannam@127: type number = N of num cannam@127: cannam@127: let makeNum n = N n cannam@127: cannam@127: (* decimal digits of precision to maintain internally, and to print out: *) cannam@127: let precision = 50 cannam@127: let print_precision = 45 cannam@127: cannam@127: let inveps = (Int 10) **/ (Int precision) cannam@127: let epsilon = (Int 1) // inveps cannam@127: cannam@127: let pinveps = (Int 10) **/ (Int print_precision) cannam@127: let pepsilon = (Int 1) // pinveps cannam@127: cannam@127: let round x = epsilon */ (round_num (x */ inveps)) cannam@127: cannam@127: let of_int n = N (Int n) cannam@127: let zero = of_int 0 cannam@127: let one = of_int 1 cannam@127: let two = of_int 2 cannam@127: let mone = of_int (-1) cannam@127: cannam@127: (* comparison predicate for real numbers *) cannam@127: let equal (N x) (N y) = (* use both relative and absolute error *) cannam@127: let absdiff = abs_num (x -/ y) in cannam@127: absdiff <=/ pepsilon || cannam@127: absdiff <=/ pepsilon */ (abs_num x +/ abs_num y) cannam@127: cannam@127: let is_zero = equal zero cannam@127: let is_one = equal one cannam@127: let is_mone = equal mone cannam@127: let is_two = equal two cannam@127: cannam@127: cannam@127: (* Note that, in the following computations, it is important to round cannam@127: to precision epsilon after each operation. Otherwise, since the cannam@127: Num package uses exact rational arithmetic, the number of digits cannam@127: quickly blows up. *) cannam@127: let mul (N a) (N b) = makeNum (round (a */ b)) cannam@127: let div (N a) (N b) = makeNum (round (a // b)) cannam@127: let add (N a) (N b) = makeNum (round (a +/ b)) cannam@127: let sub (N a) (N b) = makeNum (round (a -/ b)) cannam@127: cannam@127: let negative (N a) = (a = 1.0) then (f' -. (float (truncate f'))) else f' cannam@127: in let q = string_of_int (truncate(f2 *. 1.0E9)) cannam@127: in let r = "0000000000" ^ q cannam@127: in let l = String.length r cannam@127: in let prefix = if (f < 0.0) then "KN" else "KP" in cannam@127: if (f' >= 1.0) then cannam@127: (prefix ^ (string_of_int (truncate f')) ^ "_" ^ cannam@127: (String.sub r (l - 9) 9)) cannam@127: else cannam@127: (prefix ^ (String.sub r (l - 9) 9)) cannam@127: cannam@127: let to_string (N n) = approx_num_fix print_precision n cannam@127: cannam@127: let to_float (N n) = float_of_num n cannam@127: