# IEEE is ported from the C++ "double-conversions" library. # # The following is their license: # Copyright 2012 the V8 project authors. All rights reserved. # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions are # met: # # * Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # * Redistributions in binary form must reproduce the above # copyright notice, this list of conditions and the following # disclaimer in the documentation and/or other materials provided # with the distribution. # * Neither the name of Google Inc. nor the names of its # contributors may be used to endorse or promote products derived # from this software without specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. @[Deprecated] module Float::Printer::IEEE extend self EXPONENT_MASK_64 = 0x7FF0000000000000_u64 SIGNIFICAND_MASK_64 = 0x000FFFFFFFFFFFFF_u64 HIDDEN_BIT_64 = 0x0010000000000000_u64 # Excludes the hidden bit PHYSICAL_SIGNIFICAND_SIZE_64 = 52 SIGNIFICAND_SIZE_64 = 53 EXPONENT_BIAS_64 = 0x3FF + PHYSICAL_SIGNIFICAND_SIZE_64 DENORMAL_EXPONENT_64 = -EXPONENT_BIAS_64 + 1 SIGN_MASK_64 = 0x8000000000000000_u64 EXPONENT_MASK_32 = 0x7F800000_u32 SIGNIFICAND_MASK_32 = 0x007FFFFF_u32 HIDDEN_BIT_32 = 0x00800000_u32 # Excludes the hidden bit PHYSICAL_SIGNIFICAND_SIZE_32 = 23 SIGNIFICAND_SIZE_32 = 24 EXPONENT_BIAS_32 = 0x7F + PHYSICAL_SIGNIFICAND_SIZE_32 DENORMAL_EXPONENT_32 = -EXPONENT_BIAS_32 + 1 SIGN_MASK_32 = 0x80000000_u32 def to_uint(v : Float64) : UInt64 v.unsafe_as(UInt64) end def to_uint(v : Float32) : UInt32 v.unsafe_as(UInt32) end def sign(d64 : UInt64) : Int32 (d64 & SIGN_MASK_64) == 0 ? 1 : -1 end def sign(d32 : UInt32) : Int32 (d32 & SIGN_MASK_32) == 0 ? 1 : -1 end def special?(d64 : UInt64) : Bool (d64 & EXPONENT_MASK_64) == EXPONENT_MASK_64 end def special?(d32 : UInt32) : Bool (d32 & EXPONENT_MASK_32) == EXPONENT_MASK_32 end def inf?(d64 : UInt64) : Bool special?(d64) && (d64 & SIGNIFICAND_MASK_64 == 0) end def inf?(d32 : UInt32) : Bool special?(d32) && (d32 & SIGNIFICAND_MASK_32 == 0) end def nan?(d64 : UInt64) special?(d64) && (d64 & SIGNIFICAND_MASK_64 != 0) end def nan?(d32 : UInt32) special?(d32) && (d32 & SIGNIFICAND_MASK_32 != 0) end # Computes the two boundaries of *v*. # # The bigger boundary (*m_plus*) is normalized. The lower boundary has the same # exponent as *m_plus*. # # Precondition: the value encoded by this `Float` must be greater than 0. def normalized_boundaries(v : Float64) : {minus: DiyFP, plus: DiyFP} w = DiyFP.from_f(v) m_plus = DiyFP.new((w.frac << 1) + 1, w.exp - 1).normalize d64 = to_uint(v) # The boundary is closer if the significand is of the form f == 2^p-1 then # the lower boundary is closer. # Think of v = 1000e10 and v- = 9999e9. # Then the boundary (== (v - v-)/2) is not just at a distance of 1e9 but # at a distance of 1e8. # The only exception is for the smallest normal: the largest denormal is # at the same distance as its successor. # Note: denormals have the same exponent as the smallest normals. physical_significand_is_zero = (d64 & SIGNIFICAND_MASK_64) == 0 lower_bound_closer = physical_significand_is_zero && (exponent(d64) != DENORMAL_EXPONENT_64) f, e = if lower_bound_closer {(w.frac << 2) - 1, w.exp - 2} else {(w.frac << 1) - 1, w.exp - 1} end m_minus = DiyFP.new(f << (e - m_plus.exp), m_plus.exp) {minus: m_minus, plus: m_plus} end def normalized_boundaries(v : Float32) : {minus: DiyFP, plus: DiyFP} w = DiyFP.from_f(v) m_plus = DiyFP.new((w.frac << 1) + 1, w.exp - 1).normalize d32 = to_uint(v) physical_significand_is_zero = (d32 & SIGNIFICAND_MASK_32) == 0 lower_bound_closer = physical_significand_is_zero && (exponent(d32) != DENORMAL_EXPONENT_32) f, e = if lower_bound_closer {(w.frac << 2) - 1, w.exp - 2} else {(w.frac << 1) - 1, w.exp - 1} end m_minus = DiyFP.new(f << (e - m_plus.exp), m_plus.exp) {minus: m_minus, plus: m_plus} end def frac_and_exp(v : Float64) : {UInt64, Int32} d64 = to_uint(v) if (d64 & EXPONENT_MASK_64) == 0 # denormal float frac = d64 & SIGNIFICAND_MASK_64 exp = 1 - EXPONENT_BIAS_64 else frac = (d64 & SIGNIFICAND_MASK_64) + HIDDEN_BIT_64 exp = (((d64 & EXPONENT_MASK_64) >> PHYSICAL_SIGNIFICAND_SIZE_64) &- EXPONENT_BIAS_64).to_i! end {frac, exp} end def frac_and_exp(v : Float32) : {UInt64, Int32} d32 = to_uint(v) if (d32 & EXPONENT_MASK_32) == 0 # denormal float frac = d32 & SIGNIFICAND_MASK_32 exp = 1 - EXPONENT_BIAS_32 else frac = (d32 & SIGNIFICAND_MASK_32) + HIDDEN_BIT_32 exp = (((d32 & EXPONENT_MASK_32) >> PHYSICAL_SIGNIFICAND_SIZE_32) &- EXPONENT_BIAS_32).to_i! end {frac.to_u64, exp} end private def denormal?(d64 : UInt64) : Bool (d64 & EXPONENT_MASK_64) == 0 end private def denormal?(d32 : UInt32) : Bool (d32 & EXPONENT_MASK_32) == 0 end private def exponent(d64 : UInt64) return DENORMAL_EXPONENT_64 if denormal?(d64) biased_e = ((d64 & EXPONENT_MASK_64) >> PHYSICAL_SIGNIFICAND_SIZE_64).to_i biased_e - EXPONENT_BIAS_64 end private def exponent(d32 : UInt32) return DENORMAL_EXPONENT_32 if denormal?(d32) biased_e = ((d32 & EXPONENT_MASK_32) >> PHYSICAL_SIGNIFICAND_SIZE_32).to_i biased_e - EXPONENT_BIAS_32 end end