c++ - 有没有一种方法可以将数字作为字符串,并且不使用 float 或 double,将其四舍五入到精确的位数?

标签 c++

我有一个非常大的十进制数字作为字符串,它无法用 float 或 double 准确表示,因此我无法使用任何与数字一起使用的函数,我必须将数字保留为字符串,并使用字符串。

例如:PI:

string pI = round("3.141592653589793239", 6);

将返回“3.141593”

精度通常指的是位数,因此我的答案的精度为 7,所以我将其称为“小数位”,以免混淆这个问题。

我意识到我可以编写一个函数来执行此操作,并且我正在研究它,但我想询问执行此操作的最准确方法,到目前为止这不是我的代码,我将其归咎于我的头痛,但我花了太多时间寻找解决方案,陷入使用这个库和那个库的困境,而似乎应该有一个库可以做到这一点,而不使用 float 学,我已经看过在一些任意精度算术库中,并且无法弄清楚如何设置小数位数,并尝试使用精度,但停滞不前,因为它给我的数字在低范围,0-42 位小数之间。

我在 Qt Qml Felgo 应用程序中使用它,因此我将通过 C++ 后端调用从 Qml JavaScript 调用它。

更新: 编写我的字符串圆形函数很快就变得丑陋,需要检查的东西太多,它就像听起来一样简单,直到您开始对其进行测试。

看着

CLN:https://ginac.de/CLN/cln.html

MPIR:https://github.com/wbhart/mpir

GMP 的一个分支:http://gmplib.org/

TTMath BigNum:https://sourceforge.net/projects/ttmath/

我遇到了 Boost 的问题,并以错误报告结束, 我想我可以编写自己的圆形函数, 这样我就可以使用他们的图书馆,但这有什么意义, 无论我使用什么库,我对准确性都有要求, 和小数点位置。

需要数学的人,需要一个可以满足他们所有需求的数学库,并且四舍五入到特定的小数位是给定的,但我很难在任何库中找到可以实现此目的的函数好吧,所以我必须测试每个库,这并不容易,首先你必须学习如何使用它,如果它没有按照你想象的方式工作,你最终会花费更多的时间,就像我正在做的那样在这里,试图弄清楚这一点,相信我,我阅读了所有关于使用大数字的帖子,特别是我能找到的 float ,但它们都没有真正处理任意小数点精度,这意味着以特定的小数进行数学计算精度,大多数人认为越多就越准确,这不是我的情况,我正在寻找一种数学方法,它将返回正确的数字而不是它的估计值,float 和 long double 是我无法使用的估计值,它偏离了 100 英里,这让我很烦恼,但并不像错误的估计那么严重,boost 给了我正确的数字,我只是不知道如何使用精度来调整位数,而这并不是真正的 boost 事情,因为他们从来没有认为添加一个函数来设置小数位足够重要,所以我认识的人很少关心精度,他们只关心它有多少个小数位,并且具体返回一组小数位,而不必使用精度来做到这一点,我认为如果我取左侧的长度或整数侧,并向其添加精度,它应该起作用,我错了,结果也是如此,所以我真正需要什么是一个理解这一点的库。

我现在认识到,每个计算器实际上最多只是一个估算器。

我确实找到了一个可以处理数字的库,但没有尝试过,但这里要完整的是:

https://www.codewars.com/kata/5324945e2ece5e1f32000370

我喜欢 libmpdec 的概念,所以我现在就开始研究它。

我最终使用了https://github.com/MikeMcl/bignumber.js 它在 Qml 中工作得很好,只需将“bignumber.js”导入为 BigNumberJs, 并按照说明进行操作。

感谢您的帮助。

最佳答案

鉴于您需要精确的小数位,您提到的所有库要么超出范围,要么需要设置荒谬的精度级别以保证您的结果准确舍入。

问题是它们都基于二进制浮点,因此当您指定精度时,例如在 GMP/MPIR 中使用 mpf_set_default_prec (或 MPFR, a fork of GMP that provides more guarantees on exact, portable precision 中的等效调用),您表示将使用多少位作为有效数(粗略地说,在它之前存在多少位整数精度)按指数缩放)。虽然与十进制精度有一个粗略的对应关系(因此对于大多数用途来说,对所需精度的每一位十进制数字使用四位有效数通常就足够了),但缺乏十进制精度意味着始终需要显式输出舍入以避免错误精度,并且始终存在舍入不一致的风险:逻辑上以 5 结尾且应遵守舍入规则(例如舍入半偶数、舍入半上舍入或舍入半下舍入)的数字可能最终为错误的精度使其看起来不完全以 5 结尾,因此不应用舍入规则。

你想要的是一个decimal数学库,比如Java的BigDecimal、Python的decimal等。C/C++ standard library for this is libmpdecmpdecimal package的核心(在 Python 3.3+ 上,这是十进制模块的后端,因此您可以在 C/C++ 项目中使用它之前在 Python 上试验它的行为)。由于它是基于十进制的,因此您可以保证精度水平;如果将精度设置为 4,模式设置为 ROUND_HALF_EVEN,则解析 "XX.X45" 将始终生成 "XX.X4",而"XX.X75" 将始终生成 "XX.X8" (最后的 5 将下一位数字四舍五入为偶数)。您还可以“量化”以舍入到小数点后的特定精度(因此您的精度可能是 100,以允许小数点左右两侧组合 100 位数字,但您可以相对于“0.0000”进行量化,以强制将小数点右侧四舍五入到四位数)。

重点是,如果您想对 C/C++ 中表示实数的字符串执行精确的十进制舍入,请查看 libmpdec

对于您的特定用例,代码的 Python 版本(使用 the moneyfmt recipe ,因为像 "1.1E-26" 这样的格式数字以避免科学记数法很痛苦)看起来大致像:

from decimal import localcontext

def round_string(s, digits, rounding=None):
    '''
    Round string s representing a decimal floating point number to the specific digits of precision

    rounding is the current context's default mode if passed as None, otherwise
    any decimal module rounding mode is accepted.
    '''
    s = s.strip()  # Remove whitespace to get "real" length of string
    with localcontext() as ctx:
        # For inputs that may be in scientific notation, it's kind of annoying to
        # determine required precision, so we make a stab at it that's almost always
        # overestimating, but should work consistently
        decpart, sep, exp = s.lower().partition('e')
        ctx.prec = len(decpart) + digits + (abs(int(exp)) if sep else 0)
        if rounding is not None:
            ctx.rounding = rounding
        return moneyfmt(ctx.create_decimal(s), digits, sep='')

显然,等效的 C++ 代码会稍微复杂一些,但不一定复杂很多; Moneyfmt 配方可以简化,以避免处理一堆我们不需要的货币事物,如果不需要处理科学记数法,精度计算会更简单。无论如何,libmpdec 是 Python 3.3+ 的 decimal 包的最终来源,因此所有这些都可以完成,并保证与IEEE 754 十进制浮点规范。

关于c++ - 有没有一种方法可以将数字作为字符串,并且不使用 float 或 double,将其四舍五入到精确的位数?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55483064/

相关文章:

c++ - Node.JS,C++ 模块 : why I have segfault when I try to call Length method of Local<Array>?

c++ - std::vector(InputIterator first, InputIterator last) 是线性时间复杂度吗?

c++ - 访问数组内容时出错

c++ - 关于删除指针的问题。它应该从哪个类中删除?

c++ - googletest:死亡测试:单个测试中有多个 expect_exit

c++ - vb.net 和 c++/clr 数组长度

c++ - 如何从源代码构建glibcxx 3.4.21?

c++ - std::set 中包含 std::map 的迭代器

c++ - 在 .cpp 和 .h 中包含 header 的区别

c++ - 多线程与多处理