C++ C++;以10为基数的函数有效+;双精度指数计算

C++ C++;以10为基数的函数有效+;双精度指数计算,c++,C++,我需要使用以下结构表示数字。这种结构的目的是不损失精度 struct PreciseNumber { long significand; int exponent; } 使用此结构,实际的双精度值可以表示为值=有效位*10e^指数 现在我需要写一个实用函数,它可以将double转换成precisenNumber 您能告诉我如何从双精度中提取指数和有效位吗?这是一个非常困难的问题。您可能希望了解实现双精度到字符串转换(例如,对于printf)需要多少代码。您可能会从gnu的gcc实现

我需要使用以下结构表示数字。这种结构的目的是不损失精度

struct PreciseNumber
{
   long significand;
   int exponent;
}
使用此结构,实际的双精度值可以表示为
值=有效位*10e^指数

现在我需要写一个实用函数,它可以将double转换成precisenNumber


您能告诉我如何从双精度中提取指数和有效位吗?

这是一个非常困难的问题。您可能希望了解实现双精度到字符串转换(例如,对于printf)需要多少代码。您可能会从gnu的gcc实现中窃取代码。

这是一个非常困难的问题。您可能希望了解实现双精度到字符串转换(例如,对于printf)需要多少代码。您可能会从gnu的gcc实现中窃取代码。

您无法将“不精确”的双精度转换为“精确”的十进制数,因为根本不存在所需的“精度”(否则,您为什么还要转换?)

如果您在Java中尝试类似的操作,就会出现这种情况:

BigDecimal x = new BigDecimal(0.1);
System.out.println(x);
程序的输出为:

0.1000000000000000055511151231257827021181583404541015625
您无法将“不精确”的双精度数转换为“精确”的十进制数,因为所需的“精度”根本不存在(否则,您为什么还要转换?)

如果您在Java中尝试类似的操作,就会出现这种情况:

BigDecimal x = new BigDecimal(0.1);
System.out.println(x);
程序的输出为:

0.1000000000000000055511151231257827021181583404541015625

你比一般的替身更精确。你的有效位是一个很长的范围,从-20亿到+20亿,超过9位,但不到10位

struct PreciseNumber
{
   long significand;
   int exponent;
}
这里有一个未经测试的起点,关于你想要做的一些关于精确数字的简单数学

PreciseNumber Multiply(PreciseNumber lhs, PreciseNumber rhs)
{
  PreciseNumber ret;
  ret.s=lhs.s;
  ret.e=lhs.e;
  ret.s*=rhs.s;
  ret.e+=lhs.e;
  return ret;
}

PreciseNumber Add(PreciseNumber lhs, PreciseNumber rhs)
{
  PreciseNumber ret;
  ret.s=lhs.s;
  ret.e=lhs.e;
  ret.s+=(rhs.s*pow(10,rhs.e-lhs.e));
}

我没有考虑任何重整化,但在这两种情况下,都有一些地方需要担心过流/欠流和精度损失。仅仅因为你是自己做的,而不是让计算机一次两次地处理它,并不意味着没有同样的陷阱。唯一不丢失精度的方法是跟踪所有数字。

嗯,你的精度比典型的双精度低。你的有效位是一个很长的范围,从-20亿到+20亿,超过9位,但不到10位

struct PreciseNumber
{
   long significand;
   int exponent;
}
这里有一个未经测试的起点,关于你想要做的一些关于精确数字的简单数学

PreciseNumber Multiply(PreciseNumber lhs, PreciseNumber rhs)
{
  PreciseNumber ret;
  ret.s=lhs.s;
  ret.e=lhs.e;
  ret.s*=rhs.s;
  ret.e+=lhs.e;
  return ret;
}

PreciseNumber Add(PreciseNumber lhs, PreciseNumber rhs)
{
  PreciseNumber ret;
  ret.s=lhs.s;
  ret.e=lhs.e;
  ret.s+=(rhs.s*pow(10,rhs.e-lhs.e));
}

我没有考虑任何重整化,但在这两种情况下,都有一些地方需要担心过流/欠流和精度损失。仅仅因为你是自己做的,而不是让计算机一次两次地处理它,并不意味着没有同样的陷阱。不丢失精度的唯一方法是跟踪所有数字。

这里有一个非常粗略的算法。我稍后会尽量补充一些细节

取数字的log10得到指数。如果是正数,则将双精度乘以10^-x;如果是负数,则将双精度除以10^-x

以零的有效位开始。重复以下15次,因为双精度包含15位重要数字:

  • 将上一个有效位乘以10
  • 取double的整数部分,将其添加到有效位,然后从double中减去它
  • 从指数中减去1
  • 把这个倍数乘以10

完成后,取剩余的双精度值并使用它进行舍入:如果
=5
,则在有效位上添加一个。

这里有一个非常粗略的算法。我稍后会尽量补充一些细节

取数字的log10得到指数。如果是正数,则将双精度乘以10^-x;如果是负数,则将双精度除以10^-x

以零的有效位开始。重复以下15次,因为双精度包含15位重要数字:

  • 将上一个有效位乘以10
  • 取double的整数部分,将其添加到有效位,然后从double中减去它
  • 从指数中减去1
  • 把这个倍数乘以10

完成后,取剩余的双精度值并将其用于四舍五入:如果
=5
,则在有效位上添加一个。

前奏部分有点缺陷

首先,除非对存储空间有任何限制,否则从双精度到基10有效位指数形式的转换不会以任何形式改变精度。要理解这一点,请考虑以下问题:任何二进制终结部分(如在典型IEEE-74浮点上形成尾数的)可以被写成两个负幂之和。二的每一个负幂本身就是一个终止分数,因此它们的和也必须终止

然而,反过来并不一定正确。例如,
0.3
base 10相当于base 2中的非终止
0.01 0011 0011 0011…
。将其放入一个固定大小的尾数会使其失去一些精度(这就是为什么
0.3
实际上存储为可转换回
0.299999999999

由此,我们可以假设,以十进制有效位指数形式存储数字所需的任何精度要么丢失,要么根本无法获得


当然,您可能会认为将十进制数存储为浮点数所产生的明显精度损失是精度损失,在这种情况下,小数32和小数64浮点格式可能会引起一些兴趣—请查看。

前奏部分有点缺陷

首先,除非对存储空间有任何限制,否则从双精度到基10有效位指数形式的转换不会以任何形式改变精度。要理解这一点,请考虑以下问题:任何二进制终结部分(如在典型IEEE-74浮点上形成尾数的)可被写入TW的负幂和之和。