Extracting the exponent and mantissa of a Javascript Number

后端 未结 8 668
执笔经年
执笔经年 2020-12-03 03:03

Is there a reasonably fast way to extract the exponent and mantissa from a Number in Javascript?

AFAIK there\'s no way to get at the bits behind a Number in Javascri

8条回答
  •  孤街浪徒
    2020-12-03 03:54

    Integer factorization is nowhere near necessary for this.

    The exponent is basically going to be the floor of the base-2 logarithm, which isn't that hard to compute.

    The following code passes QuickCheck tests, as well as tests on infinity and negative infinity:

    minNormalizedDouble :: Double
    minNormalizedDouble = 2 ^^ (-1022)
    
    powers :: [(Int, Double)]
    powers = [(b, 2.0 ^^ fromIntegral b) | i <- [9, 8..0], let b = bit i]
    
    exponentOf :: Double -> Int
    exponentOf d
      | d < 0   = exponentOf (-d)
      | d < minNormalizedDouble = -1024
      | d < 1   = 
          let go (dd, accum) (p, twoP)
                | dd * twoP < 1 = (dd * twoP, accum - p)
                | otherwise = (dd, accum)
          in snd $ foldl' go (d, 0) powers
      | otherwise   =
          let go (x, accum) (p, twoP)
                | x * twoP <= d = (x * twoP, accum + p)
                | otherwise = (x, accum)
        in 1 + (snd $ foldl' go (1.0, 0) powers)
    
    
    decode :: Double -> (Integer, Int)
    decode 0.0 = (0, 0)
    decode d
      | isInfinite d, d > 0 = (4503599627370496, 972)
      | isInfinite d, d < 0 = (-4503599627370496, 972)
      | isNaN d             = (-6755399441055744, 972)
      | otherwise       =
          let
            e = exponentOf d - 53
            twoE = 2.0 ^^ e
             in (round (d / twoE), e)
    

    I tested it using quickCheck (\ d -> decodeFloat d == decode d), and explicitly tested it separately on positive and negative infinities.

    The only primitive operations used here are left-shift, double multiplication, double division, and infinity and NaN testing, which Javascript supports to the best of my knowledge.

提交回复
热议问题