help-smalltalk
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Help-smalltalk] Re: [PATCH] Fraction and Integer asFloat: answer ne


From: Paolo Bonzini
Subject: Re: [Help-smalltalk] Re: [PATCH] Fraction and Integer asFloat: answer nearest floating point
Date: Sun, 28 Jan 2007 22:35:31 +0100
User-agent: Thunderbird 1.5.0.9 (Macintosh/20061207)

Thanks, I applied a pretty big patch with all your changes and mine.

Paolo
2007-01-27  Paolo Bonzini  <address@hidden>
            Nicolas Cellier  <address@hidden>

        * kernel/Float.st: Rewrite #truncated and #asExactFraction.
        * kernel/Fraction.st: Use #asFloatD in #hash.  Rewrite #asFloat:.
        * kernel/LargeInt.st: Rewrite #asFloat:.  Add #trailingZeros.
        * kernel/SmallInt.st: Add #trailingZeros.
        * kernel/Integer.st: Add #trailingZeros.
        * kernel/MappedColl.st: Use map size as collection size.

        * tests/floatmath.st: Add accuracy tests.
        * tests/floatmath.ok: Adjust.
 
2007-01-27  Paolo Bonzini  <address@hidden>

        * lib-src/truncl.c: New.

2007-01-28  Paolo Bonzini  <address@hidden>

        * libgst/prims.def: Use truncl and lrint to implement
        conversion from float to integer.


--- orig/NEWS
+++ mod/NEWS
@@ -27,6 +27,9 @@ o   #copyFrom:to: is uniformly 0-based f
 o   Fixed a garbage collection bug that typically occurred when installing
     GNU Smalltalk, or when launching the installed image.
 
+o   Fixed many floating point rounding bugs in LargeIntegers and Fractions,
+    thanks to Nicolas Cellier.
+
 o   gst-package honors the INSTALL command found by configure.
 
 o   gst-config does not "forget" to prefix the library directories with -L.


--- orig/configure.ac
+++ mod/configure.ac
@@ -204,7 +204,7 @@ AC_CHECK_LIB(m, atan)
 GST_REPLACE_POLL
 AC_REPLACE_FUNCS(putenv strdup strerror strsignal mkstemp getpagesize \
        getdtablesize strstr ftruncate floorl ceill sqrtl frexpl ldexpl asinl \
-       acosl atanl logl expl tanl sinl cosl strsep strpbrk)
+       acosl atanl logl expl tanl sinl cosl truncl strsep strpbrk)
 AC_CHECK_FUNCS_ONCE(gethostname memcpy memmove sighold uname sbrk usleep lstat 
\
        grantpt popen getrusage gettimeofday getcwd fork strchr \
        sigsetmask alarm select mprotect madvise nl_langinfo waitpid \


--- orig/kernel/Float.st
+++ mod/kernel/Float.st
@@ -194,27 +194,30 @@ truncated
         ifFalse: [ float := self negated ].
 
     exponent := float exponent.
-    bytes := ByteArray new: exponent // 8 + 2.
-    float := float timesTwoPower: (exponent bitClear: 7) negated.
+    bytes := LargePositiveInteger new: (self class precision + 7) // 8 + 1.
+    float := float timesTwoPower: float class precision - exponent - 8.
 
-    bytes size - 1 to: 1 by: -1 do: [ :i |
-         bytes at: i put: float truncated.
-         float := float fractionPart timesTwoPower: 8
+    1 to: bytes size do: [ :i |
+         bytes digitAt: i put: (float fractionPart timesTwoPower: 8) truncated.
+         float := float integerPart timesTwoPower: -8.
     ].
 
-    ^positive
-        ifTrue: [ (LargeInteger from: bytes) ]
-        ifFalse: [ (LargeInteger from: bytes) negated ]
+    bytes := bytes bitShift: (exponent - float class precision).
+    positive ifFalse: [ bytes := bytes negated ].
+    ^bytes
 !
 
 asExactFraction
     "Convert the receiver into a fraction with optimal approximation,
      but with usually huge terms."
 
+    | shift mantissa |
     self checkCoercion.
-
-    ^(self timesTwoPower: self exponent + self class precision) truncated /
-     (1    bitShift:      self exponent + self class precision)
+    shift := self exponent negated + self class precision.
+    mantissa := (self timesTwoPower: shift) truncated.
+    ^shift negative
+        ifTrue: [mantissa * (1 bitShift: shift negated)]
+        ifFalse: [mantissa / (1 bitShift: shift)]
 !
 
 asFraction


--- orig/kernel/Fraction.st
+++ mod/kernel/Fraction.st
@@ -288,7 +288,7 @@ truncated
 hash
     "Answer an hash value for the receiver"
     denominator = 1 ifTrue: [ ^numerator hash ].
-    ^(numerator asFloatD / denominator asFloatD) hash
+    ^self asFloatD hash
 ! !
 
 
@@ -385,33 +385,59 @@ storeOn: aStream
 
 asFloat: characterization
     "Answer the receiver converted to a Float"
-    | n d shift sign |
-    n := numerator.
-    d := denominator.
-    sign := n sign * d sign.
-
-    "Avoid answering NaNs and infinite values.
-     1e1800 asFloat / (1e1799 + 1) asFloat = NaN, but
-     (1e1800 / (1e1799 + 1)) asFloat must be 10."
-
-    shift := (characterization emax - numerator highBit).
-    shift := shift min: (characterization emax - denominator highBit).
-    shift < 0 ifTrue: [
-       "Lose some more precision, but we MUST avoid infinites and NaNs!"
-       shift := shift - 10. n := n bitShift: shift. d := d bitShift: shift ].
-
-    d = 0 ifTrue: [
-       ^sign > 0
-           ifTrue: [ characterization infinity ]
-           ifFalse: [ characterization negativeInfinity ] ].
-    n = 0 ifTrue: [
-       ^sign > 0
-           ifTrue: [ characterization coerce: 0 ]
-           ifFalse: [ characterization negativeInfinity reciprocal ] ].
+    "Answer the receiver converted to a Float"
 
-    ^(characterization coerce: n)
-        / (characterization coerce: d)
-!
+    | n d sign hn hd hq nBits q q1 r exponent floatExponent | 
+    sign := numerator sign * denominator sign.
+    n := numerator abs.
+    d := denominator abs.
+    hn := n highBit.
+    hd := d highBit.
+
+    "If both numerator and denominator are represented exactly in floating
+     point number, then fastest thing to do is to use hardwired float division"
+    nBits := characterization precision + 1.
+    (hn < nBits and: [hd < nBits]) 
+        ifTrue: [^(characterization coerce: numerator) / (characterization 
coerce: denominator)].
+
+    "Try and obtain a mantissa with characterization precision + 1 bits by 
integer division.
+     Additional bit is a helper for rounding mode.
+     First guess is rough, we might get one more bit or one less"
+    exponent := hn - hd - nBits.
+    exponent > 0 
+        ifTrue: [d := d bitShift: exponent]
+        ifFalse: [n := n bitShift: exponent negated].
+    q := n quo: d.
+    r := n - (q * d).
+    hq := q highBit.
+
+    "check for gradual underflow, in which case we should use less bits"
+    floatExponent := exponent + hq.
+    floatExponent >= (characterization emin - 1) ifFalse: [nBits := nBits + 
floatExponent - characterization emin+1].
+
+    "Use exactly nBits"
+    hq > nBits 
+        ifTrue: 
+            [exponent := exponent + hq - nBits.
+            r := (q bitAnd: (1 bitShift: hq - nBits) - 1) * d + r.
+            q := q bitShift: nBits - hq].
+    hq < nBits 
+        ifTrue: 
+            [exponent := exponent + hq - nBits.
+            q1 := (r bitShift: nBits - hq) quo: d.
+            q := (q bitShift: nBits - hq) bitAnd: q1.
+            r := (r bitShift: nBits - hq) - (q1 * d)].
+
+    "check if we should round upward.
+    The case of exact half (q bitAnd: 1) = 1 & (r = 0)
+    will be handled by Integer>>asFloat:"
+    ((q bitAnd: 1) = 0 or: [r = 0]) ifFalse: [q := q + 1].
+
+    "build the Float"
+    ^(sign > 0
+        ifTrue: [characterization coerce: q]
+        ifFalse: [(characterization coerce: q) negated]) 
+            timesTwoPower: exponent!
 
 reduce
     "Reduce the fraction."


--- orig/kernel/Integer.st
+++ mod/kernel/Integer.st
@@ -139,12 +139,18 @@ clearBit: index
 !
 
 noMask: anInteger
-    "True if no 1 bits in anInteger are 1 in the receiver"
+    "Answer true if no 1 bits in anInteger are 1 in the receiver."
     ^(self bitAnd: anInteger) = 0
 !
 
+trailingZeros
+    "Return the index of the lowest order 1 bit of the receiver,
+     minus 1."
+    self subclassResponsibility
+!
+
 highBit
-    "Return the index of the highest order 1 bit of the receiver"
+    "Return the index of the highest order 1 bit of the receiver."
     self subclassResponsibility
 !
 


--- orig/kernel/LargeInt.st
+++ mod/kernel/LargeInt.st
@@ -493,6 +493,17 @@ negated
 
 !LargeInteger methodsFor: 'bit operations'!
 
+trailingZeros
+    "Answer the number of trailing zero bits in the receiver"
+
+    | each |
+    1 to: self size do: [ :index |
+        (each := self digitAt: index) = 0
+            ifFalse: [ ^index * 8 - 8 + (TrailingZeros at: each) ].
+    ].
+    ^self highBit - 1
+!
+
 bitAnd: aNumber
     "Answer the receiver ANDed with aNumber"
     | newBytes |
@@ -977,17 +988,32 @@ sign
 asFloat: characterization
     "Answer the receiver converted to a Float"
 
-    | adjust result byte |
+    | nTruncatedBits mantissa exponent mask trailingBits inexact carry | 
+
+    "Check for number bigger than maximum mantissa"
+    nTruncatedBits := self highBit - characterization precision.
+    nTruncatedBits <= 0 
+        ifTrue: [^self fastAsFloat: characterization ].
+
+    mantissa := self bitShift: nTruncatedBits negated.
+    exponent := nTruncatedBits.
+
+    "Apply IEEE 754 round to nearest even default rounding mode"
+    carry := self bitAt: nTruncatedBits.
+    (carry = 1 and: [mantissa odd or: [self trailingZeros >= nTruncatedBits]]) 
+        ifTrue: [mantissa := mantissa + 1].
+    ^(characterization coerce: mantissa) timesTwoPower: exponent!
+
+fastAsFloat: characterization
+    "Conversion can be exact, construct Float by successive mul add operations"
+    | result byte |
     byte := characterization coerce: 256.
-    adjust := byte raisedToInteger: self size - 1.
-    result := 0.
+    result := characterization coerce: 0.
 
     self size to: 1 by: -1 do: [ :index |
-       result := (self at: index) * adjust + result.
-       adjust := adjust / byte.
+       result := result * byte + (self at: index).
     ].
-    ^result
-!
+    ^result!
 
 mostSignificantByte
     "Private - Answer the value of the most significant byte"


--- orig/kernel/MappedColl.st
+++ mod/kernel/MappedColl.st
@@ -89,7 +89,7 @@ at: key put: value
 
 size
     "Answer the receiver's size"
-    ^domain size
+    ^map size
 !
 
 add: anObject


--- orig/kernel/SmallInt.st
+++ mod/kernel/SmallInt.st
@@ -94,6 +94,24 @@ generality
 
 !SmallInteger methodsFor: 'bit arithmetic'!
 
+trailingZeros
+    "Return the index of the trailing zero bits in the receiver"
+
+    | n bit |
+    self = 0 ifTrue: [ ^0 ].
+
+    n := self.
+    bit := 0.
+
+    (n bitAnd: 16r3FFFFFFF) = 0 ifTrue: [
+       bit := bit + 30. n := n bitShift: -30 ].
+
+    (n bitAnd: 16rFFFF) = 0 ifTrue: [ bit := bit + 16. n := n bitShift: -16 ].
+    (n bitAnd: 16rFF) = 0 ifTrue: [ bit := bit + 8. n := n bitShift: -8 ].
+    (n bitAnd: 16rF) = 0 ifTrue: [ bit := bit + 4. n := n bitShift: -4 ].
+    (n bitAnd: 16r3) = 0 ifTrue: [ bit := bit + 2. n := n bitShift: -2 ].
+    ^bit + (1 - (n bitAnd: 16r1))!
+
 highBit
     "Return the index of the highest order 1 bit of the receiver"
 


--- orig/libgst/prims.def
+++ mod/libgst/prims.def
@@ -1531,14 +1531,9 @@ primitive VMpr_FloatD_truncated [succeed
   if COMMON (RECEIVER_IS_CLASS (oop1, _gst_floatd_class))
     {
       double oopValue = FLOATD_OOP_VALUE (oop1);
-      if COMMON (oopValue >= 0.0 && oopValue <= MAX_ST_INT)
+      if COMMON (oopValue >= MIN_ST_INT && oopValue <= MAX_ST_INT)
        {
-         PUSH_INT ((intptr_t) (oopValue + 0.000000000000005));
-         PRIM_SUCCEEDED;
-       }
-      else if COMMON (oopValue < 0.0 && oopValue >= MIN_ST_INT)
-       {
-         PUSH_INT ((intptr_t) (oopValue - 0.000000000000005));
+         PUSH_INT (lrint (trunc (oopValue)));
          PRIM_SUCCEEDED;
        }
     }
@@ -1732,14 +1727,9 @@ primitive VMpr_FloatE_truncated [succeed
   if COMMON (RECEIVER_IS_CLASS (oop1, _gst_floate_class))
     {
       double oopValue = FLOATE_OOP_VALUE (oop1);
-      if COMMON (oopValue >= 0.0 && oopValue <= MAX_ST_INT)
+      if COMMON (oopValue >= MIN_ST_INT && oopValue <= MAX_ST_INT)
        {
-         PUSH_INT ((intptr_t) (oopValue + 0.000000000000005));
-         PRIM_SUCCEEDED;
-       }
-      else if COMMON (oopValue < 0.0 && oopValue >= MIN_ST_INT)
-       {
-         PUSH_INT ((intptr_t) (oopValue - 0.000000000000005));
+         PUSH_INT (lrintf (truncf (oopValue)));
          PRIM_SUCCEEDED;
        }
     }
@@ -1933,14 +1923,9 @@ primitive VMpr_FloatQ_truncated [succeed
   if COMMON (RECEIVER_IS_CLASS (oop1, _gst_floatq_class))
     {
       long double oopValue = FLOATQ_OOP_VALUE (oop1);
-      if COMMON (oopValue >= 0.0 && oopValue <= MAX_ST_INT)
-       {
-         PUSH_INT ((intptr_t) (oopValue + 0.000000000000005));
-         PRIM_SUCCEEDED;
-       }
-      else if COMMON (oopValue < 0.0 && oopValue >= MIN_ST_INT)
+      if COMMON (oopValue >= MIN_ST_INT && oopValue <= MAX_ST_INT)
        {
-         PUSH_INT ((intptr_t) (oopValue - 0.000000000000005));
+         PUSH_INT (lrintl (truncl (oopValue)));
          PRIM_SUCCEEDED;
        }
     }


--- orig/tests/floatmath.ok
+++ mod/tests/floatmath.ok
@@ -1,248 +1,74 @@
-
-Execution begins...
-returned value is 3.10000
-
-Execution begins...
-returned value is 3.45000
-
-Execution begins...
-returned value is 30000.0
-
-Execution begins...
-returned value is 34500.0
-
-Execution begins...
-returned value is 7.70000
-
-Execution begins...
-returned value is -8.62000
-
-Execution begins...
-returned value is false
-
-Execution begins...
-returned value is true
-
-Execution begins...
-returned value is true
-
-Execution begins...
-returned value is false
-
-Execution begins...
-returned value is true
-
-Execution begins...
-returned value is true
-
-Execution begins...
-returned value is true
-
-Execution begins...
-returned value is true
-
-Execution begins...
-returned value is 0.00180000
-
-Execution begins...
-returned value is 11250.0
-
-Execution begins...
-returned value is 3
-
-Execution begins...
-returned value is 0.141593
-
-Execution begins...
-returned value is 12
-
-Execution begins...
-returned value is 720.000
-
-Execution begins...
-returned value is 2.81250
-
-Execution begins...
-returned value is inf
-
-Execution begins...
-returned value is 'Inf'
-
-Execution begins...
-returned value is -inf
-
-Execution begins...
-returned value is '-Inf'
-
-Execution begins...
-returned value is nan
-
-Execution begins...
-returned value is 'NaN'
-
-Execution begins...
-returned value is '0.0'
-
-Execution begins...
-returned value is '-0.0'
-
-Execution begins...
-returned value is true
-
-Execution begins...
-returned value is false
-
-Execution begins...
-returned value is nan
-
-Execution begins...
-returned value is nan
-
-Execution begins...
-returned value is nan
-
-Execution begins...
-returned value is 5.00000
-
-Execution begins...
-returned value is 5.00000
-
-Execution begins...
-returned value is 7.00000
-
-Execution begins...
-returned value is 0.00000
-
-Execution begins...
-returned value is -0.00000
-
-Execution begins...
-returned value is -0.00000
-
-Execution begins...
-returned value is -0.00000
-
-Execution begins...
-returned value is nan
-
-Execution begins...
-returned value is nan
-
-Execution begins...
-returned value is nan
-
-Execution begins...
-returned value is 7.00000
-
-Execution begins...
-returned value is 7.00000
-
-Execution begins...
-returned value is 7.00000
-
-Execution begins...
-returned value is 0.00000
-
-Execution begins...
-returned value is 0.00000
-
-Execution begins...
-returned value is 0.00000
-
-Execution begins...
-returned value is -0.00000
-
-Execution begins...
-returned value is true
-
-Execution begins...
-returned value is true
-
-Execution begins...
-returned value is true
-
-Execution begins...
-returned value is true
-
-Execution begins...
-returned value is true
-
-Execution begins...
-returned value is true
-
-Execution begins...
-returned value is true
-
-Execution begins...
-returned value is true
-
-Execution begins...
-(-0.0 -0.0 0.0 0.0 true 0.0 0.0 true )
-(-0.0 0.0 0.0 0.0 true -0.0 -0.0 true )
-(0.0 -0.0 -0.0 -0.0 true 0.0 0.0 true )
-(0.0 0.0 0.0 0.0 true 0.0 0.0 true )
-returned value is Array new: 4 "<0>"
-
-Execution begins...
-(-0.0 -0.0 0.0 0.0 true 0.0 0.0 true )
-(-0.0 0.0 0.0 0.0 true -0.0 -0.0 true )
-(0.0 -0.0 -0.0 -0.0 true 0.0 0.0 true )
-(0.0 0.0 0.0 0.0 true 0.0 0.0 true )
-returned value is Array new: 4 "<0>"
-
-Execution begins...
-(-0.0 -0.0 0.0 0.0 true 0.0 0.0 true )
-(0.0 0.0 0.0 0.0 true 0.0 0.0 true )
-returned value is Array new: 2 "<0>"
-
-Execution begins...
-(-0.0 0.0 true true true )
-(0.0 -0.0 true true true )
-returned value is Array new: 2 "<0>"
-
-Execution begins...
-returned value is Float
-
-Execution begins...
-true->1.0e16
-returned value is 1.00000e+16
-
-Execution begins...
-true->1.2345e16
-returned value is 1.23450e+16
-
-Execution begins...
-true->10.0
-returned value is 10.0000
-
-Execution begins...
-true->17.7674749
-returned value is 17.7675
-
-Execution begins...
-true->0.12345
-returned value is 0.123450
-
-Execution begins...
-true->0.0000000012345
-returned value is 1.23450d-09
-
-Execution begins...
-true->1.2345e-9
-returned value is 1.23450e-09
-
-Execution begins...
-true->0.83205029433784
-returned value is 0.832050
-
-Execution begins...
-true->0.832050294337844
-returned value is 0.832050
-
-Execution begins...
-true->0.55470019622523
-returned value is 0.554700
-
-Execution begins...
-true->0.554700196225229
-returned value is 0.554700
+*** floatmath.ok       Wed Nov  8 11:54:47 2006
+--- /Volumes/disk0s8/devel/gst/+build/tests/floatmath.log      Sun Jan 28 
22:31:28 2007
+***************
+*** 204,213 ****
+--- 204,221 ----
+  returned value is Float
+  
+  Execution begins...
++ true->10000000000000000.0
++ returned value is 1.00000d+16
++ 
++ Execution begins...
+  true->1.0e16
+  returned value is 1.00000e+16
+  
+  Execution begins...
++ true->12345000000000000.0
++ returned value is 1.23450d+16
++ 
++ Execution begins...
+  true->1.2345e16
+  returned value is 1.23450e+16
+  
+***************
+*** 246,248 ****
+--- 254,301 ----
+  Execution begins...
+  true->0.554700196225229
+  returned value is 0.554700
++ 
++ Execution begins...
++ returned value is Float class
++ 
++ Execution begins...
++ true
++ true
++ true
++ true
++ true
++ true
++ true
++ true
++ true
++ true
++ true
++ true
++ true
++ true
++ true
++ true
++ true
++ true
++ returned value is FloatD
++ 
++ Execution begins...
++ true
++ true
++ true
++ true
++ true
++ true
++ true
++ true
++ true
++ true
++ true
++ true
++ true
++ true
++ true
++ true
++ true
++ true
++ returned value is FloatE


--- orig/tests/floatmath.st
+++ mod/tests/floatmath.st
@@ -8,7 +8,7 @@
 
 "======================================================================
 |
-| Copyright (C) 1988, 1989, 1999, 2006  Free Software Foundation.
+| Copyright (C) 1988, 1989, 1999, 2006, 2007  Free Software Foundation.
 | Written by Steve Byrne
 |
 | This file is part of GNU Smalltalk.
@@ -168,7 +168,9 @@ test
     (((Behavior evaluate: self printString) = self) -> self) printNl. 
 ! !
 
+1d16 test!
 1e16 test!
+1.2345d16 test!
 1.2345e16 test!
 10.0 test!
 (20 - 2.2325251) test!
@@ -179,3 +181,55 @@ test
 0.832050294337844 test!
 0.55470019622523 test!
 0.554700196225229 test!
+
+
+"Fun with rounding"
+
+!Float class methodsFor: 'testing'!
+
+assert: aBoolean
+    aBoolean ifFalse: [ self halt ] ifTrue: [ aBoolean printNl ]!
+
+test
+    | p |
+    p := 1 bitShift: self precision - 1.
+    self assert: (self coerce: p+0+(1/4)) asExactFraction = (p+0).
+    self assert: (self coerce: p+0+(1/2)) asExactFraction = (p+0).
+    self assert: (self coerce: p+0+(3/4)) asExactFraction = (p+1).
+    self assert: (self coerce: p+1+(1/4)) asExactFraction = (p+1).
+    self assert: (self coerce: p+1+(1/2)) asExactFraction = (p+2).
+    self assert: (self coerce: p+1+(3/4)) asExactFraction = (p+2).
+    
+    self assert: ((self emin - self precision - 1 to: self emax - 1) 
allSatisfy: [:i |
+        p := (self coerce: 1) timesTwoPower: i.
+       (self coerce: p asExactFraction) = p]).
+    
+    self assert: ((1 to: 1 + self precision - self emin) allSatisfy: [:i |
+        p := (self coerce: 1) timesTwoPower: i negated.
+       (self coerce: (1 bitShift: i) reciprocal negated) = p negated]).
+    
+    "check for negative zero"
+    p := 1 bitShift: 1 + self precision - self emin.
+    self assert: (self coerce: p reciprocal) positive.
+    self assert: (self coerce: p reciprocal negated) negative.
+    
+    "check for infinity"
+    p := 1 bitShift: self emax + 1.
+    self assert: (self coerce: p) = self infinity.
+    self assert: (self coerce: p negated) = self negativeInfinity.
+    
+    p := 1 bitShift: 1 + self precision - self emin.
+    self assert: (self coerce: p / 3) = self infinity.
+    self assert: (self coerce: p / -3) = self negativeInfinity.
+    
+    "check for non infinity/nan"
+    p := 1 bitShift: self emax + 1.
+    self assert: (self coerce: p / 3) isFinite.
+    self assert: (self coerce: p / -3) isFinite.
+    
+    p := 1 bitShift: 1 + self precision - self emin.
+    self assert: (self coerce: 3 / p) isFinite.
+    self assert: (self coerce: -3 / p) isFinite! !
+
+FloatD test!
+FloatE test!



* added files

--- /dev/null
+++ 
/Volumes/disk0s8/devel/gst/,,address@hidden/new-files-archive/./lib-src/.arch-ids/truncl.c.id
@@ -0,0 +1 @@
+Paolo Bonzini <address@hidden> Sun Jan 28 22:17:40 2007 18819.0
--- /dev/null
+++ 
/Volumes/disk0s8/devel/gst/,,address@hidden/new-files-archive/./lib-src/truncl.c
@@ -0,0 +1,79 @@
+/******************************** -*- C -*- ****************************
+ *
+ *      Emulation for truncl
+ *
+ *
+ ***********************************************************************/
+
+/***********************************************************************
+ *
+ * Copyright 2007 Free Software Foundation, Inc.
+ * Written by Paolo Bonzini.
+ *
+ * This file is part of GNU Smalltalk.
+ *
+ * GNU Smalltalk is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2, or (at your option) any later
+ * version.
+ *
+ * Linking GNU Smalltalk statically or dynamically with other modules is
+ * making a combined work based on GNU Smalltalk.  Thus, the terms and
+ * conditions of the GNU General Public License cover the whole
+ * combination.
+ *
+ * In addition, as a special exception, the Free Software Foundation
+ * give you permission to combine GNU Smalltalk with free software
+ * programs or libraries that are released under the GNU LGPL and with
+ * independent programs running under the GNU Smalltalk virtual machine.
+ *
+ * You may copy and distribute such a system following the terms of the
+ * GNU GPL for GNU Smalltalk and the licenses of the other code
+ * concerned, provided that you include the source code of that other
+ * code when and as the GNU GPL requires distribution of source code.
+ *
+ * Note that people who make modified versions of GNU Smalltalk are not
+ * obligated to grant this special exception for their modified
+ * versions; it is their choice whether to do so.  The GNU General
+ * Public License gives permission to release a modified version without
+ * this exception; this exception also makes it possible to release a
+ * modified version which carries forward this exception.
+ *
+ * GNU Smalltalk is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * GNU Smalltalk; see the file COPYING.  If not, write to the Free Software
+ * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ ***********************************************************************/
+
+#include <float.h>
+
+#include "mathl.h"
+
+/* To compute the integer part of X, sum a big enough
+   integer so that the precision of the floating point
+   number is exactly 1.  */
+
+long double
+truncl(long double x)
+{
+  long double y;
+  if (x < 0.0L)
+    {
+      y = -(1.0L / LDBL_EPSILON - x - 1.0 / LDBL_EPSILON);
+      if (y < x)
+        y = y + 1.0L;
+    }
+  else
+    {
+      y = 1.0L / LDBL_EPSILON + x - 1.0 / LDBL_EPSILON;
+      if (y > x)
+        y = y - 1.0L;
+    }
+
+  return y;
+}


reply via email to

[Prev in Thread] Current Thread [Next in Thread]