|
| 1 | +" |
| 2 | +A `PMFloatingPointMachine` represents the numerical precision of this system. |
| 3 | +
|
| 4 | +##Instance Variables |
| 5 | +
|
| 6 | +- `defaultNumericalPrecision` The relative numerical precision that can be expected for a general numerical computation. One should consider to numbers a and b equal if the relative difference between them is less than the default machine precision, |
| 7 | +- `largestExponentArgument` Natural logarithm of largest number, |
| 8 | +- `largestNumber` The largest positive number that can be represented in the machine, |
| 9 | +- `machinePrecision` $r^{-(n+1)}$, with the largest n such that $(1 + r^{-n}) - 1$ != 0, |
| 10 | +- `negativeMachinePrecision` $r^{-(n+1)}$, with the largest n such that $(1 - r^{-n}) - 1$ != 0, |
| 11 | +- `radix` The radix of the floating point representation. This is often 2, |
| 12 | +- `smallNumber` A number that can be added to some value without noticeably changing the result of the computation, |
| 13 | +- `smallestNumber` The smallest positive number different from 0. |
| 14 | +
|
| 15 | +This class is detailed in Object Oriented Implementation of Numerical Methods, Section 1.4.1 and 1.4.2. |
| 16 | +
|
| 17 | +" |
| 18 | +Class { |
| 19 | + #name : #PMFloatingPointMachine, |
| 20 | + #superclass : #Object, |
| 21 | + #instVars : [ |
| 22 | + 'defaultNumericalPrecision', |
| 23 | + 'radix', |
| 24 | + 'machinePrecision', |
| 25 | + 'negativeMachinePrecision', |
| 26 | + 'smallestNumber', |
| 27 | + 'largestNumber', |
| 28 | + 'smallNumber', |
| 29 | + 'largestExponentArgument' |
| 30 | + ], |
| 31 | + #classVars : [ |
| 32 | + 'UniqueInstance' |
| 33 | + ], |
| 34 | + #category : #'Math-Core' |
| 35 | +} |
| 36 | + |
| 37 | +{ #category : #'instance creation' } |
| 38 | +PMFloatingPointMachine class >> new [ |
| 39 | + UniqueInstance ifNil: [ UniqueInstance := super new ]. |
| 40 | + ^ UniqueInstance |
| 41 | +] |
| 42 | + |
| 43 | +{ #category : #accessing } |
| 44 | +PMFloatingPointMachine class >> reset [ |
| 45 | + UniqueInstance := nil |
| 46 | +] |
| 47 | + |
| 48 | +{ #category : #information } |
| 49 | +PMFloatingPointMachine >> computeLargestNumber [ |
| 50 | + |
| 51 | + | one floatingRadix fullMantissaNumber | |
| 52 | + one := 1.0. |
| 53 | + floatingRadix := self radix asFloat. |
| 54 | + fullMantissaNumber := one - ( floatingRadix * self negativeMachinePrecision). |
| 55 | + largestNumber := fullMantissaNumber. |
| 56 | + [ [ fullMantissaNumber := fullMantissaNumber * floatingRadix. |
| 57 | + fullMantissaNumber isInfinite ifTrue: [^nil]. |
| 58 | + largestNumber := fullMantissaNumber. |
| 59 | + true] whileTrue: [ ]. |
| 60 | + ] on: Error do: [ :signal | signal return: nil] |
| 61 | +] |
| 62 | + |
| 63 | +{ #category : #information } |
| 64 | +PMFloatingPointMachine >> computeMachinePrecision [ |
| 65 | + |
| 66 | + | one zero inverseRadix tmp | |
| 67 | + one := 1.0. |
| 68 | + zero := 0.0. |
| 69 | + inverseRadix := one / self radix asFloat. |
| 70 | + machinePrecision := one. |
| 71 | + [ tmp := one + machinePrecision. |
| 72 | + tmp - one = zero] |
| 73 | + whileFalse:[ machinePrecision := machinePrecision * inverseRadix] |
| 74 | +] |
| 75 | + |
| 76 | +{ #category : #information } |
| 77 | +PMFloatingPointMachine >> computeNegativeMachinePrecision [ |
| 78 | + |
| 79 | + | one zero floatingRadix inverseRadix tmp | |
| 80 | + one := 1.0. |
| 81 | + zero := 0.0. |
| 82 | + floatingRadix := self radix asFloat. |
| 83 | + inverseRadix := one / floatingRadix. |
| 84 | + negativeMachinePrecision := one. |
| 85 | + [ tmp := one - negativeMachinePrecision. |
| 86 | + tmp - one = zero] |
| 87 | + whileFalse:[ negativeMachinePrecision := negativeMachinePrecision * inverseRadix] |
| 88 | +] |
| 89 | + |
| 90 | +{ #category : #information } |
| 91 | +PMFloatingPointMachine >> computeRadix [ |
| 92 | + |
| 93 | + | one zero a b tmp1 tmp2| |
| 94 | + one := 1.0. |
| 95 | + zero := 0.0. |
| 96 | + a := one. |
| 97 | + [ a := a + a. |
| 98 | + tmp1 := a + one. |
| 99 | + tmp2 := tmp1 - a. |
| 100 | + tmp2 - one = zero] whileTrue:[]. |
| 101 | + b := one. |
| 102 | + [ b := b + b. |
| 103 | + tmp1 := a + b. |
| 104 | + radix := ( tmp1 - a) truncated. |
| 105 | + radix = 0 ] whileTrue: [] |
| 106 | +] |
| 107 | + |
| 108 | +{ #category : #information } |
| 109 | +PMFloatingPointMachine >> computeSmallestNumber [ |
| 110 | + |
| 111 | + | one floatingRadix inverseRadix fullMantissaNumber | |
| 112 | + one := 1 asFloat. |
| 113 | + floatingRadix := self radix asFloat. |
| 114 | + inverseRadix := one / floatingRadix. |
| 115 | + fullMantissaNumber := one - (floatingRadix * self negativeMachinePrecision). |
| 116 | + smallestNumber := fullMantissaNumber. |
| 117 | + [[fullMantissaNumber := fullMantissaNumber * inverseRadix. |
| 118 | + fullMantissaNumber = 0.0 ifTrue: [Error signal ]. |
| 119 | + smallestNumber := fullMantissaNumber. |
| 120 | + true] |
| 121 | + whileTrue: []] |
| 122 | + on: Error do: [:signal | signal return: nil] |
| 123 | +] |
| 124 | + |
| 125 | +{ #category : #information } |
| 126 | +PMFloatingPointMachine >> defaultNumericalPrecision [ |
| 127 | + |
| 128 | + defaultNumericalPrecision isNil |
| 129 | + ifTrue: [ defaultNumericalPrecision := self machinePrecision sqrt]. |
| 130 | + ^defaultNumericalPrecision |
| 131 | +] |
| 132 | + |
| 133 | +{ #category : #information } |
| 134 | +PMFloatingPointMachine >> largestExponentArgument [ |
| 135 | + |
| 136 | + largestExponentArgument isNil |
| 137 | + ifTrue: [ largestExponentArgument := self largestNumber ln]. |
| 138 | + ^largestExponentArgument |
| 139 | +] |
| 140 | + |
| 141 | +{ #category : #information } |
| 142 | +PMFloatingPointMachine >> largestNumber [ |
| 143 | + |
| 144 | + largestNumber isNil |
| 145 | + ifTrue: [ self computeLargestNumber]. |
| 146 | + ^largestNumber |
| 147 | +] |
| 148 | + |
| 149 | +{ #category : #information } |
| 150 | +PMFloatingPointMachine >> machinePrecision [ |
| 151 | + |
| 152 | + machinePrecision isNil |
| 153 | + ifTrue: [ self computeMachinePrecision]. |
| 154 | + ^machinePrecision |
| 155 | +] |
| 156 | + |
| 157 | +{ #category : #information } |
| 158 | +PMFloatingPointMachine >> negativeMachinePrecision [ |
| 159 | + |
| 160 | + negativeMachinePrecision isNil |
| 161 | + ifTrue: [ self computeNegativeMachinePrecision]. |
| 162 | + ^negativeMachinePrecision |
| 163 | +] |
| 164 | + |
| 165 | +{ #category : #information } |
| 166 | +PMFloatingPointMachine >> radix [ |
| 167 | + |
| 168 | + radix isNil |
| 169 | + ifTrue: [ self computeRadix]. |
| 170 | + ^radix |
| 171 | +] |
| 172 | + |
| 173 | +{ #category : #display } |
| 174 | +PMFloatingPointMachine >> showParameters [ |
| 175 | + |
| 176 | + Transcript cr; cr; |
| 177 | + nextPutAll: 'Floating-point machine parameters'; cr; |
| 178 | + nextPutAll: '---------------------------------';cr; |
| 179 | + nextPutAll: 'Radix: '. |
| 180 | + self radix printOn: Transcript. |
| 181 | + Transcript cr; nextPutAll: 'Machine precision: '. |
| 182 | + self machinePrecision printOn: Transcript. |
| 183 | + Transcript cr; nextPutAll: 'Negative machine precision: '. |
| 184 | + self negativeMachinePrecision printOn: Transcript. |
| 185 | + Transcript cr; nextPutAll: 'Smallest number: '. |
| 186 | + self smallestNumber printOn: Transcript. |
| 187 | + Transcript cr; nextPutAll: 'Largest number: '. |
| 188 | + self largestNumber printOn: Transcript. |
| 189 | + Transcript flush |
| 190 | +] |
| 191 | + |
| 192 | +{ #category : #information } |
| 193 | +PMFloatingPointMachine >> smallNumber [ |
| 194 | + |
| 195 | + smallNumber isNil |
| 196 | + ifTrue: [ smallNumber := self smallestNumber sqrt]. |
| 197 | + ^smallNumber |
| 198 | +] |
| 199 | + |
| 200 | +{ #category : #information } |
| 201 | +PMFloatingPointMachine >> smallestNumber [ |
| 202 | + |
| 203 | + smallestNumber isNil |
| 204 | + ifTrue: [ self computeSmallestNumber]. |
| 205 | + ^smallestNumber |
| 206 | +] |
0 commit comments