我有一个非常大的十进制数字作为字符串,它无法用 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 libmpdec
,mpdecimal
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/