|
| 1 | +/* ef_fmod.c -- float version of e_fmod.c. |
| 2 | + * Conversion to float by Ian Lance Taylor, Cygnus Support, [email protected]. |
| 3 | + */ |
| 4 | + |
| 5 | +/* |
| 6 | + * ==================================================== |
| 7 | + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. |
| 8 | + * |
| 9 | + * Developed at SunPro, a Sun Microsystems, Inc. business. |
| 10 | + * Permission to use, copy, modify, and distribute this |
| 11 | + * software is freely granted, provided that this notice |
| 12 | + * is preserved. |
| 13 | + * ==================================================== |
| 14 | + */ |
| 15 | + |
| 16 | +const ONE: f32 = 1.0f32; |
| 17 | +const ZERO: [f32; 2] = [0.0f32, -0.0]; |
| 18 | + |
| 19 | +/// Return `x mod y` in exact arithmetic. |
| 20 | +/// |
| 21 | +/// Method: shift and subtract |
| 22 | +#[inline] |
| 23 | +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] |
| 24 | +pub fn fmodf(x: f32, y: f32) -> f32 { |
| 25 | + use super::fdlibm::{ |
| 26 | + FLT_UWORD_IS_FINITE, FLT_UWORD_IS_NAN, FLT_UWORD_IS_SUBNORMAL, FLT_UWORD_IS_ZERO, |
| 27 | + }; |
| 28 | + const U32_BITS: u8 = 32; |
| 29 | + let mut n: i32; |
| 30 | + let mut hx: u32; |
| 31 | + let mut hy: u32; |
| 32 | + let mut hz: i32; |
| 33 | + let mut ix: i32; |
| 34 | + let mut iy: i32; |
| 35 | + let sx: u32; |
| 36 | + let mut i: i32; |
| 37 | + |
| 38 | + hx = x.to_bits(); |
| 39 | + sx = hx & 0x80000000; /* sign of x */ |
| 40 | + hx ^= sx; /* |x| */ |
| 41 | + hy = y.to_bits() & 0x7fffffff; /* |y| */ |
| 42 | + |
| 43 | + /* purge off exception values */ |
| 44 | + if FLT_UWORD_IS_ZERO(hy) || !FLT_UWORD_IS_FINITE(hx) || FLT_UWORD_IS_NAN(hy) { |
| 45 | + return (x * y) / (x * y); |
| 46 | + } |
| 47 | + if hx < hy { |
| 48 | + return x; /* |x|<|y| return x */ |
| 49 | + } |
| 50 | + if hx == hy { |
| 51 | + return ZERO[sx as usize >> (U32_BITS - 1)]; /* |x|=|y| return x*0 */ |
| 52 | + } |
| 53 | + |
| 54 | + /* Note: y cannot be zero if we reach here. */ |
| 55 | + |
| 56 | + /* determine ix = ilogb(x) */ |
| 57 | + if FLT_UWORD_IS_SUBNORMAL(hx) { |
| 58 | + /* subnormal x */ |
| 59 | + ix = -126; |
| 60 | + i = (hx << 8) as i32; |
| 61 | + while i > 0 { |
| 62 | + ix -= 1; |
| 63 | + i <<= 1; |
| 64 | + } |
| 65 | + } else { |
| 66 | + ix = (hx >> 23) as i32 - 127; |
| 67 | + } |
| 68 | + |
| 69 | + /* determine iy = ilogb(y) */ |
| 70 | + if FLT_UWORD_IS_SUBNORMAL(hy) { |
| 71 | + /* subnormal y */ |
| 72 | + iy = -126; |
| 73 | + i = (hy << 8) as i32; |
| 74 | + while i >= 0 { |
| 75 | + iy -= 1; |
| 76 | + i <<= 1; |
| 77 | + } |
| 78 | + } else { |
| 79 | + iy = (hy >> 23) as i32 - 127; |
| 80 | + } |
| 81 | + |
| 82 | + /* set up {hx,lx}, {hy,ly} and align y to x */ |
| 83 | + if ix >= -126 { |
| 84 | + hx = 0x0080_0000 | (0x007f_ffff & hx); |
| 85 | + } else { |
| 86 | + /* subnormal x, shift x to normal */ |
| 87 | + n = -126 - ix; |
| 88 | + hx <<= n; |
| 89 | + } |
| 90 | + if iy >= -126 { |
| 91 | + hy = 0x0080_0000 | (0x007f_ffff & hy); |
| 92 | + } else { |
| 93 | + /* subnormal y, shift y to normal */ |
| 94 | + n = -126 - iy; |
| 95 | + hy <<= n; |
| 96 | + } |
| 97 | + |
| 98 | + /* fix point fmod */ |
| 99 | + n = ix - iy; |
| 100 | + while n != 0 { |
| 101 | + hz = hx.wrapping_sub(hy) as i32; |
| 102 | + if hz < 0 { |
| 103 | + hx += hx; |
| 104 | + } else { |
| 105 | + if hz == 0 { |
| 106 | + /* return sign(x)*0 */ |
| 107 | + return ZERO[sx as usize >> (U32_BITS - 1)]; |
| 108 | + } |
| 109 | + hx = (hz + hz) as u32; |
| 110 | + } |
| 111 | + n -= 1; |
| 112 | + } |
| 113 | + hz = hx.wrapping_sub(hy) as i32; |
| 114 | + if hz >= 0 { |
| 115 | + hx = hz as u32; |
| 116 | + } |
| 117 | + |
| 118 | + /* convert back to floating value and restore the sign */ |
| 119 | + if hx == 0 { |
| 120 | + /* return sign(x)*0 */ |
| 121 | + return ZERO[sx as usize >> (U32_BITS - 1)]; |
| 122 | + } |
| 123 | + while hx < 0x0080_0000 { |
| 124 | + /* normalize x */ |
| 125 | + hx += hx; |
| 126 | + iy -= 1; |
| 127 | + } |
| 128 | + if iy >= -126 { |
| 129 | + /* normalize output */ |
| 130 | + hx = (hx.wrapping_sub(0x0080_0000)) | ((iy + 127) << 23) as u32; |
| 131 | + f32::from_bits(hx | sx) |
| 132 | + } else { |
| 133 | + /* subnormal output */ |
| 134 | + /* If denormals are not supported, this code will generate a zero representation. */ |
| 135 | + n = -126 - iy; |
| 136 | + hx >>= n; |
| 137 | + /* create necessary signal */ |
| 138 | + f32::from_bits(hx | sx) * ONE |
| 139 | + } |
| 140 | +} |
0 commit comments