annotate src/fftw-3.3.3/genfft/number.ml @ 83:ae30d91d2ffe

Replace these with versions built using an older toolset (so as to avoid ABI compatibilities when linking on Ubuntu 14.04 for packaging purposes)
author Chris Cannam
date Fri, 07 Feb 2020 11:51:13 +0000
parents 37bf6b4a2645
children
rev   line source
Chris@10 1 (*
Chris@10 2 * Copyright (c) 1997-1999 Massachusetts Institute of Technology
Chris@10 3 * Copyright (c) 2003, 2007-11 Matteo Frigo
Chris@10 4 * Copyright (c) 2003, 2007-11 Massachusetts Institute of Technology
Chris@10 5 *
Chris@10 6 * This program is free software; you can redistribute it and/or modify
Chris@10 7 * it under the terms of the GNU General Public License as published by
Chris@10 8 * the Free Software Foundation; either version 2 of the License, or
Chris@10 9 * (at your option) any later version.
Chris@10 10 *
Chris@10 11 * This program is distributed in the hope that it will be useful,
Chris@10 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
Chris@10 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
Chris@10 14 * GNU General Public License for more details.
Chris@10 15 *
Chris@10 16 * You should have received a copy of the GNU General Public License
Chris@10 17 * along with this program; if not, write to the Free Software
Chris@10 18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Chris@10 19 *
Chris@10 20 *)
Chris@10 21
Chris@10 22 (* The generator keeps track of numeric constants in symbolic
Chris@10 23 expressions using the abstract number type, defined in this file.
Chris@10 24
Chris@10 25 Our implementation of the number type uses arbitrary-precision
Chris@10 26 arithmetic from the built-in Num package in order to maintain an
Chris@10 27 accurate representation of constants. This allows us to output
Chris@10 28 constants with many decimal places in the generated C code,
Chris@10 29 ensuring that we will take advantage of the full precision
Chris@10 30 available on current and future machines.
Chris@10 31
Chris@10 32 Note that we have to write our own routine to compute roots of
Chris@10 33 unity, since the Num package only supplies simple arithmetic. The
Chris@10 34 arbitrary-precision operations in Num look like the normal
Chris@10 35 operations except that they have an appended slash (e.g. +/ -/ */
Chris@10 36 // etcetera). *)
Chris@10 37
Chris@10 38 open Num
Chris@10 39
Chris@10 40 type number = N of num
Chris@10 41
Chris@10 42 let makeNum n = N n
Chris@10 43
Chris@10 44 (* decimal digits of precision to maintain internally, and to print out: *)
Chris@10 45 let precision = 50
Chris@10 46 let print_precision = 45
Chris@10 47
Chris@10 48 let inveps = (Int 10) **/ (Int precision)
Chris@10 49 let epsilon = (Int 1) // inveps
Chris@10 50
Chris@10 51 let pinveps = (Int 10) **/ (Int print_precision)
Chris@10 52 let pepsilon = (Int 1) // pinveps
Chris@10 53
Chris@10 54 let round x = epsilon */ (round_num (x */ inveps))
Chris@10 55
Chris@10 56 let of_int n = N (Int n)
Chris@10 57 let zero = of_int 0
Chris@10 58 let one = of_int 1
Chris@10 59 let two = of_int 2
Chris@10 60 let mone = of_int (-1)
Chris@10 61
Chris@10 62 (* comparison predicate for real numbers *)
Chris@10 63 let equal (N x) (N y) = (* use both relative and absolute error *)
Chris@10 64 let absdiff = abs_num (x -/ y) in
Chris@10 65 absdiff <=/ pepsilon or
Chris@10 66 absdiff <=/ pepsilon */ (abs_num x +/ abs_num y)
Chris@10 67
Chris@10 68 let is_zero = equal zero
Chris@10 69 let is_one = equal one
Chris@10 70 let is_mone = equal mone
Chris@10 71 let is_two = equal two
Chris@10 72
Chris@10 73
Chris@10 74 (* Note that, in the following computations, it is important to round
Chris@10 75 to precision epsilon after each operation. Otherwise, since the
Chris@10 76 Num package uses exact rational arithmetic, the number of digits
Chris@10 77 quickly blows up. *)
Chris@10 78 let mul (N a) (N b) = makeNum (round (a */ b))
Chris@10 79 let div (N a) (N b) = makeNum (round (a // b))
Chris@10 80 let add (N a) (N b) = makeNum (round (a +/ b))
Chris@10 81 let sub (N a) (N b) = makeNum (round (a -/ b))
Chris@10 82
Chris@10 83 let negative (N a) = (a </ (Int 0))
Chris@10 84 let negate (N a) = makeNum (minus_num a)
Chris@10 85
Chris@10 86 let greater a b = negative (sub b a)
Chris@10 87
Chris@10 88 let epsilonsq = epsilon */ epsilon
Chris@10 89 let epsilonsq2 = (Int 100) */ epsilonsq
Chris@10 90
Chris@10 91 let sqr a = a */ a
Chris@10 92 let almost_equal (N a) (N b) = (sqr (a -/ b)) <=/ epsilonsq2
Chris@10 93
Chris@10 94 (* find square root by Newton's method *)
Chris@10 95 let sqrt a =
Chris@10 96 let rec sqrt_iter guess =
Chris@10 97 let newguess = div (add guess (div a guess)) two in
Chris@10 98 if (almost_equal newguess guess) then newguess
Chris@10 99 else sqrt_iter newguess
Chris@10 100 in sqrt_iter (div a two)
Chris@10 101
Chris@10 102 let csub (xr, xi) (yr, yi) = (round (xr -/ yr), round (xi -/ yi))
Chris@10 103 let cdiv (xr, xi) r = (round (xr // r), round (xi // r))
Chris@10 104 let cmul (xr, xi) (yr, yi) = (round (xr */ yr -/ xi */ yi),
Chris@10 105 round (xr */ yi +/ xi */ yr))
Chris@10 106 let csqr (xr, xi) = (round (xr */ xr -/ xi */ xi), round ((Int 2) */ xr */ xi))
Chris@10 107 let cabssq (xr, xi) = xr */ xr +/ xi */ xi
Chris@10 108 let cconj (xr, xi) = (xr, minus_num xi)
Chris@10 109 let cinv x = cdiv (cconj x) (cabssq x)
Chris@10 110
Chris@10 111 let almost_equal_cnum (xr, xi) (yr, yi) =
Chris@10 112 (cabssq (xr -/ yr,xi -/ yi)) <=/ epsilonsq2
Chris@10 113
Chris@10 114 (* Put a complex number to an integer power by repeated squaring: *)
Chris@10 115 let rec ipow_cnum x n =
Chris@10 116 if (n == 0) then
Chris@10 117 (Int 1, Int 0)
Chris@10 118 else if (n < 0) then
Chris@10 119 cinv (ipow_cnum x (- n))
Chris@10 120 else if (n mod 2 == 0) then
Chris@10 121 ipow_cnum (csqr x) (n / 2)
Chris@10 122 else
Chris@10 123 cmul x (ipow_cnum x (n - 1))
Chris@10 124
Chris@10 125 let twopi = 6.28318530717958647692528676655900576839433879875021164194989
Chris@10 126
Chris@10 127 (* Find the nth (complex) primitive root of unity by Newton's method: *)
Chris@10 128 let primitive_root_of_unity n =
Chris@10 129 let rec root_iter guess =
Chris@10 130 let newguess = csub guess (cdiv (csub guess
Chris@10 131 (ipow_cnum guess (1 - n)))
Chris@10 132 (Int n)) in
Chris@10 133 if (almost_equal_cnum guess newguess) then newguess
Chris@10 134 else root_iter newguess
Chris@10 135 in let float_to_num f = (Int (truncate (f *. 1.0e9))) // (Int 1000000000)
Chris@10 136 in root_iter (float_to_num (cos (twopi /. (float n))),
Chris@10 137 float_to_num (sin (twopi /. (float n))))
Chris@10 138
Chris@10 139 let cexp n i =
Chris@10 140 if ((i mod n) == 0) then
Chris@10 141 (one,zero)
Chris@10 142 else
Chris@10 143 let (n2,i2) = Util.lowest_terms n i
Chris@10 144 in let (c,s) = ipow_cnum (primitive_root_of_unity n2) i2
Chris@10 145 in (makeNum c, makeNum s)
Chris@10 146
Chris@10 147 let to_konst (N n) =
Chris@10 148 let f = float_of_num n in
Chris@10 149 let f' = if f < 0.0 then f *. (-1.0) else f in
Chris@10 150 let f2 = if (f' >= 1.0) then (f' -. (float (truncate f'))) else f'
Chris@10 151 in let q = string_of_int (truncate(f2 *. 1.0E9))
Chris@10 152 in let r = "0000000000" ^ q
Chris@10 153 in let l = String.length r
Chris@10 154 in let prefix = if (f < 0.0) then "KN" else "KP" in
Chris@10 155 if (f' >= 1.0) then
Chris@10 156 (prefix ^ (string_of_int (truncate f')) ^ "_" ^
Chris@10 157 (String.sub r (l - 9) 9))
Chris@10 158 else
Chris@10 159 (prefix ^ (String.sub r (l - 9) 9))
Chris@10 160
Chris@10 161 let to_string (N n) = approx_num_fix print_precision n
Chris@10 162
Chris@10 163 let to_float (N n) = float_of_num n
Chris@10 164