cljs.math/IEEE-remainder
function | since v1.11.50 | Edit |
(IEEE-remainder dividend divisor)
Source docstring:
Returns the remainder per IEEE 754 such that
remainder = dividend - divisor * n
where n is the integer closest to the exact value of dividend / divisor.
If two integers are equally close, then n is the even one.
If the remainder is zero, sign will match dividend.
If dividend or divisor is ##NaN, or dividend is ##Inf or ##-Inf, or divisor is zero => ##NaN
If dividend is finite and divisor is infinite => dividend
Method: based on fmod return x-[x/p]chopped*p exactlp.
Ported from: https://github.com/openjdk/jdk/blob/master/src/java.base/share/native/libfdlibm/e_remainder.c
See: https://docs.oracle.com/javase/8/docs/api/java/lang/Math.html#IEEEremainder-double-double-
(defn ^number IEEE-remainder
{:added "1.11.10"}
[dividend divisor]
;; check for exception values
(cond
(zero? divisor) ##NaN
^boolean (js/isNaN divisor) ##NaN
;; check if dividend is ##Inf ##-Inf or ##NaN
^boolean (js/isNaN dividend) ##NaN
(not ^boolean (js/isFinite dividend)) ##NaN
;; dividend is finish, check if divisor is infinite
(not ^boolean (js/isFinite divisor)) dividend
:default
;; create a buffer large enough for 2 doubles
(let [a (js/ArrayBuffer. 16)
;; represent the buffer as a double array
d (js/Float64Array. a)
;; represent the buffer as 32 bit ints
i (js/Uint32Array. a)]
(aset d 0 dividend)
(aset d 1 divisor)
;; x gets the dividend high and low ints
(let [hx (aget i HI)
lx (aget i LO)
;; p gets the divisor high and low ints
hp (aget i (+ HI 2))
lp (aget i (+ LO 2))
;; sx is the sign bit
sx (bit-and hx INT32-NON-SIGN-BIT)
;; strip the sign bit from hp and hx
hp (bit-and hp INT32-NON-SIGN-BITS)
hx (bit-and hx INT32-NON-SIGN-BITS)
;;make x < 2p
dividend (if (<= hp 0x7FDFFFFF) (IEEE-fmod dividend (+ divisor divisor)) dividend)]
(if (zero? (bit-or (- hx hp) (- lx lp)))
(* 0.0 dividend)
;; convert dividend and divisor to absolute values.
(let [dividend (Math/abs dividend)
divisor (Math/abs divisor)
;; reduce dividend within range of the divisor
dividend (if (< hp 0x00200000)
;; smaller divisor compare 2*dividend to the divisor
(if (> (+ dividend dividend) divisor)
(let [dividend (- dividend divisor)] ;; reduce the dividend
(if (>= (+ dividend dividend) divisor) ;; 2*dividend still larger
(- dividend divisor) ;; reduce again
dividend))
dividend)
;; compare dividend to half the divisor
(let [divisor-half (* 0.5 divisor)]
(if (> dividend divisor-half)
(let [dividend (- dividend divisor)] ;; reduce the dividend
(if (>= dividend divisor-half) ;; still larger than half divisor
(- dividend divisor) ;; reduce again
dividend))
dividend)))]
;; update the buffer with the new dividend value
(aset d 0 dividend)
;; calculate a new hi int for the dividend using the saved sign bit
(let [hx (bit-xor (aget i HI) sx)]
;; set the dividend with this new sign bit
(aset i HI hx)
;; retrieve the updated dividend
(aget d 0))))))))