【问题标题】:C++ set precision of a double (not for output)C ++设置双精度(不适用于输出)
【发布时间】:2018-03-07 15:48:52
【问题描述】:

好吧,所以我试图从具有给定位数精度(前后的总位数,或没有小数)的双精度数中截断实际值,而不仅仅是输出它们,而不仅仅是四舍五入。我为此找到的唯一内置函数会截断所有小数,或四舍五入到给定的小数精度。 我在网上找到的其他解决方案,只有在您知道小数点前的位数或整数时才能这样做。 该解决方案应该足够动态以处理任何数字。我编写了一些代码来完成下面的技巧,但是我无法摆脱这种感觉有更好的方法来做到这一点。有谁知道更优雅的东西?也许是我不知道的内置函数?

我应该提一下这样做的原因。观测值有 3 种不同的来源。所有这三个来源都同意某种程度的精确度。如下所示,它们都在 10 位数以内一致。 4659.96751751236 4659.96751721355 4659.96751764253 但是我只需要从其中一个来源中提取。因此,最好的方法是仅使用所有 3 个来源都同意的精度。所以它不像我在操纵数字然后需要截断精度,它们是观察值。期望的结果是 4659.967517

double truncate(double num, int digits) {

// check valid digits
if (digits < 0)
    return num;

// create string stream for full precision (string conversion rounds at 10)
ostringstream numO;

// read in number to stream, at 17+ precision things get wonky
numO << setprecision(16) << num;

// convert to string, for character manipulation
string numS = numO.str();

// check if we have a decimal
int decimalIndex = numS.find('.');

// if we have a decimal, erase it for now, logging its position
if(decimalIndex != -1)
    numS.erase(decimalIndex, 1);

// make sure our target precision is not higher than current precision
digits = min((int)numS.size(), digits);

// replace unwanted precision with zeroes
numS.replace(digits, numS.size() - digits, numS.size() - digits, '0');

// if we had a decimal, add it back
if (decimalIndex != -1)
    numS.insert(numS.begin() + decimalIndex, '.');

return atof(numS.c_str());

}

【问题讨论】:

  • 如果您知道如何舍入/截断小数点后的第一个数字,并且知道如何乘以/除以 10,那么您可以舍入/截断您喜欢的任何数字
  • (num * pow(10, n)) / pow(10, n) 会做你想做的事,但有些数字不能准确表达,所以你仍然可以得到更多的值。这样做的实际目的是什么?几乎听起来你想要一个定点库。
  • 浮点数并不是这样工作的。我会考虑使用具有 2 个整数的 Decimal 类型,一个是尾数,另一个是指数。稍后将它们操作到您想要的任何精度都非常简单:将尾数除以 pow(10,n),将 n 添加到指数
  • @tobi303 是的,我考虑过采用迭代方法除以或乘以 10,但我认为字符串可能更快。必须测试它XD
  • @EyalK。听起来很酷 =) 我唯一的问题是,与我提供的代码相比有什么优势?为了得到尾数,无论如何我都必须操纵双精度来移动小数。然后我必须存储两个代表一个的变量。总而言之,这听起来像是额外的代码行来完成同样的事情。不过我可能会遗漏一些东西..

标签: c++ set double precision truncate


【解决方案1】:

这永远不会起作用,因为 double不是十进制类型。截断你认为的一定数量的十进制数字只会在最后引入一组新的笑话数字。它甚至可能是有害的:例如0.125 是精确的 double,但 0.120.13 都不是。

如果您想使用小数,请使用小数类型,或者使用约定其一部分包含小数部分的大型整数类型。

【讨论】:

  • 这就是我在某个点截断的原因。我知道所有数字在给定的精度下都是准确的。之后数字是随机的。所以我想将它们归零,并使用正确的 Sig Figs - 直到已知的精度。
  • "之后数字是随机的。"每次我读到我内心都会死去一点。使用整数或小数类型;漂亮,请在上面加糖。
  • 我对小数类型进行了一些研究,但问题是它们只关注小数点后的精度。我需要小数点前后所有数字的总精度。小数点前的位数也不同,所以我不能硬编码。
  • 一个 quid 说 long long 就足够了吗?
  • 我明白你的意思,0.125 比 0.12 和 0.13 好,但前提是你知道 0.125 是准确的。如果你不知道 5 是否准确,最好截断并使用 .12
【解决方案2】:

我不同意“所以最好的方法是只使用所有 3 个来源都同意的精度。”

如果这些是物理量的不同测量值,或者由于测量测量值的计算方式不同而导致舍入误差,则通过取平均值而不是将它们不同意的数字强制为任何数字,您将获得对真实值的更好估计任意值,包括零。

取平均值的最终理由是Central Limit Theorem,它建议将您的测量值视为正态分布的样本。如果是这样,则样本均值是总体均值的最佳可用估计值。您的截断过程往往会低估实际值。

通常最好保留您通过计算获得的每条信息,然后记住在输出结果时您的精度有限。

除了给出更好的估计外,取三个数字的平均值是一个极其简单的计算。

【讨论】:

  • 是的,我同意平均值是最好的。但是,正如我在问题中所述,我只需要使用其中一个来源。这是为了使程序和资源尽可能轻。由于它们在一定精度后不一致,因此最好的方法是使用显着数字。所以取最好的精度,截断到准确的有效数字。
  • 即使是三个来源的随机选择也比将位或更差的十进制数字强制为零更好的估计器。
  • 我明白你在说什么,但我使用的是重要数字。这意味着我要向读者说明我不确定这些数字在某个点之后的准确性。因此,最终结果将仅显示我确信正确的数字。我在另一条评论中使用了 Pi 的示例,如果您只知道某个点的精度,您可以使用该点并在此之后截断数字。它不是用 0 代替数字,而是拒绝说明数字,因为它们可能是错误的。
  • 例如取号码4659.96751751236。 10位数字后的准确性充其量是不确定的。假设数学运算只是乘以 5。然后取数字的最小值和最大值... 4659.96751799999 * 5 = 23299.83758999995 4659.96751700000 * 5 = 23299.83758500000 所以两个输出也同意高达 10 位精度。因此,对于数学运算和结果以 10 精度截断,会产生最准确的结果。
  • 您显示的内容与您在计算中使用的内容之间存在差异。在计算过程中,您应该使用您可以获得的实际价值的最佳估计值。三个观察值的平均值比单个观察值要好,但是单个观察值比通过修改它可以得到的任何东西都更好。当您开始显示时,“10”成为一个重要的数字,将输出截断为您信任的数字是有意义的,同时考虑到原始测量误差和累积的舍入误差。
猜你喜欢
  • 2014-01-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-01-02
  • 2010-11-28
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多