Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/sql/67.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
提取Javascript数字的指数和尾数_Javascript_Math_Haskell_Ghc_Ieee 754 - Fatal编程技术网

提取Javascript数字的指数和尾数

提取Javascript数字的指数和尾数,javascript,math,haskell,ghc,ieee-754,Javascript,Math,Haskell,Ghc,Ieee 754,有没有一种相当快速的方法可以从Javascript中的数字中提取指数和尾数 好了,在Javascript中没有办法找到数字后面的位,这让我觉得我正在研究一个分解问题:找到m和n,这样2^n*m=k对于给定的k。由于整数分解是NP,我只能假设这将是一个相当困难的问题 我正在实现一个生成Javascript的GHC插件,需要实现decodeFloat\u Int和decodeddouble\u 2Int;我想我可以重写基本库中使用该操作的部分,无论它们以其他方式做什么(这应该不会太难,因为所有数字类

有没有一种相当快速的方法可以从Javascript中的数字中提取指数和尾数

好了,在Javascript中没有办法找到数字后面的位,这让我觉得我正在研究一个分解问题:找到
m
n
,这样
2^n*m=k
对于给定的
k
。由于整数分解是NP,我只能假设这将是一个相当困难的问题

我正在实现一个生成Javascript的GHC插件,需要实现
decodeFloat\u Int
decodeddouble\u 2Int
;我想我可以重写基本库中使用该操作的部分,无论它们以其他方式做什么(这应该不会太难,因为所有数字类型都以数字作为它们的表示形式),但如果我不必这样做,那就太好了

是否有任何方法可以通过一些黑暗的Javascript巫术、聪明的数学或其他方法,以一种甚至是远程执行的方式来实现这一点,或者我应该全力以赴,在基本库中使用它吗

编辑 基于ruakh和Louis Wasserman的优秀答案,我提出了以下实现,它似乎工作得很好:

function getNumberParts(x) {
    if(isNaN(x)) {
        return {mantissa: -6755399441055744, exponent: 972};
    }
    var sig = x > 0 ? 1 : -1;
    if(!isFinite(x)) {
        return {mantissa: sig * 4503599627370496, exponent: 972};
    }
    x = Math.abs(x);
    var exp = Math.floor(Math.log(x)*Math.LOG2E)-52;
    var man = x/Math.pow(2, exp);
    return {mantissa: sig*man, exponent: exp};
}

ECMAScript没有定义任何简单的方法来实现这一点;但无论如何,这不是一个与素因子分解意义相同的“因子分解问题”


从理论上讲,我们可以非常快速地完成这项工作,首先处理符号,然后使用二叉树方法(或对数)找到指数,最后除以二的相关幂得到尾数;但不幸的是,在实践中实现这一点可能有点棘手(在非规范化数字等特殊情况下)。我建议您通读ECMAScript规范的第8.5节,了解您必须处理哪些情况。

整数因子分解对此几乎没有必要

指数基本上是以2为底的对数的底数,这并不难计算

以下代码通过了快速检查测试,以及无穷大和负无穷大测试:

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)
minNormalizedDouble::Double
minNormalizedDouble=2^^(-1022)
幂::[(整数,双精度)]
幂=[(b,2.0^^from积分b)| i Int
d指数
|d<0=指数(-d)
|d|x*twoPMy Haskell不存在。这里有一个JavaScript解决方案。正如其他人所指出的,关键是计算二进制对数以获得指数

函数decodieee64(值){
如果(值的类型!=“编号”)
抛出新类型错误(“值必须是数字”);
var结果={
否:错,
指数:0,
尾数:0
};
如果(值==0){
返回结果;
}
//不是有限的?
如果(!isFinite(值)){
结果指数=2047;
如果(isNaN(值)){
result.isNegative=false;
result.尾数=2251799813685248;//QNan
}否则{
result.isNegative=值===-无穷大;
result.尾数=0;
}
返回结果;
}
//否定的?
如果(值<0){
result.isNegative=true;
值=-值;
}
//计算有偏指数
var e=0;
如果(值>=Math.pow(2,-1022)){//未非规范化
//计算二进制对数的整数部分
var r=价值;
而(r<1){e-=1;r*=2;}
而(r>=2){e+=1;r/=2;}
e+=1023;//添加偏差
}
结果:指数=e;
//计算尾数
如果(e!=0){
var f=数值/数学功率(2,e-1023);
result.尾数=Math.floor((f-1)*Math.pow(2,52));
}else{//非规范化
result.尾数=Math.floor(value/Math.pow(2,-1074));
}
返回结果;
}
< /代码> 使用新的访问数组,实际上可以从中提取精确尾数和指数,如果需要更多的速度,可以考虑重用.< /p>。

虽然我喜欢公认的解决方案,但使用它在任意基上工作会重新引入由
Math.log
Math.pow
引起的所有错误。下面是一个适用于任何基的小实现:
x=尾数*b^指数

function numberParts(x, b) {
  var exp = 0
  var sgn = 0
  if (x === 0) return { sign: 0, mantissa: 0, exponent: 0 }
  if (x<0) sgn=1, x=-x
  while (x>b) x/=b, exp++
  while (x<1) x*=b, exp--
  return { sign: sgn, mantissa: x, exponent: exp }
}

如果你只需要尾数长度

Number.prototype.尾数长度=函数(){
var m=this.toString(),d=m.indexOf('.')+1;
返回d?m.长度-d:0;
}
var x=1234.5678;
var mantL=x.尾数长度();

下面如何获取指数:

let exp = String(number.toExponential());
exp = Number(exp.substr(exp.lastIndexOf('e')+1));

1000将导致exp=3

对于基数10,您可以使用

   var myarray = (number.toExponential() + '').split("e");
   // then ...
   var mantissa = parseFloat(myarray[0]);
   var exponent = parseInt(myarray[1]);

如果您不关心结果部分是否为文本而不是数字,并且指数部分的前面可能有加号,则可以跳过
parseFloat
parseInt
步骤,直接从[0]和[1]处的数组中获取部分.

因子分解毫无疑问是NP中的一部分,只是不被认为是NP难的。你把它们混在一起了。@LouisWasserman:嗯,我在网上发现了相互矛盾的信息。我将删除我答案中的这一部分,因为它不是很重要。谢谢。谢谢你;不过,这个方法不重要吗(至少如果使用以2为底的对数来获得指数)为大多数数字给出一个非整数尾数?@valderman:这是个好问题。我习惯于认为尾数是[1.0,2.0]范围内的值,指数是[-1022,+1023]范围内的整数,但EMCAScript用术语表示数字
function numberParts(x, b) {
  var exp = 0
  var sgn = 0
  if (x === 0) return { sign: 0, mantissa: 0, exponent: 0 }
  if (x<0) sgn=1, x=-x
  while (x>b) x/=b, exp++
  while (x<1) x*=b, exp--
  return { sign: sgn, mantissa: x, exponent: exp }
}
if (1/x === Infinity) return { sign: 0, mantissa: 0, exponent: 0 }
if (1/x === -Infinity) return { sign: 1, mantissa: 0, exponent: 0 }
let exp = String(number.toExponential());
exp = Number(exp.substr(exp.lastIndexOf('e')+1));
   var myarray = (number.toExponential() + '').split("e");
   // then ...
   var mantissa = parseFloat(myarray[0]);
   var exponent = parseInt(myarray[1]);