有没有一种方法可以将数字作为字符串,而无需使用浮点数或双精度数,将其舍入为确切的数字位数?

时间:2019-04-02 20:27:25

标签: c++

我有一个很大的十进制数字作为字符串,它不能用浮点数或双精度数精确表示,所以我不能使用任何与数字一起使用的函数,我必须将数字保留为字符串,并使用字符串。

例如:PI:

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

将返回"3.141593"

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

我意识到我可以编写一个函数来执行此操作,并且我正在研究它,但是我想问一问最准确的方法,到目前为止,这不是我的代码,我将其归咎于我头疼,但是我花了太多时间寻找解决方案,陷入了使用这个库的麻烦,而那个库似乎应该有一个不使用浮点运算就可以做到这一点的库,在一些任意精度的算术库中,还无法弄清楚如何设置小数位数,并尝试使用Precision并停滞不前,因为它给我的数字在低范围,介于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和long double是我不能使用的估计,它跑了100英里,这让我感到烦恼,但不只是错误的估计,提升给了我正确的数字,只是无法弄清楚如何使用精度来调整位数,而这并不是真正的提倡,因为他们从来没有添加一个设置小数位的函数那么重要,我认识的人很少有人关心精度,只是在乎它有多少小数位,特别是无需使用精度就可以返回一定数量的小数位,我认为如果我取左侧的长度或整数的长度,并加上精度为此,它应该起作用,我错了,结果也是如此,所以我真正需要的是一个能够理解这一点的库。

我现在认为每个计算器充其量都是估算器。

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

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

我喜欢libmpdec的概念,所以我现在就解决这个问题。

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

感谢所有帮助。

1 个答案:

答案 0 :(得分:2)

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

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

您想要的是一个十进制数学库,例如Java的BigDecimal,Python的decimal等。C/C++ standard library for this is libmpdec是{{3 }}(在Python 3.3+上,这是decimal模块的后端,因此您可以在致力于在C / C ++项目中使用它之前在Python上试验其行为)。由于它是基于小数的,因此可以保证精度等级;如果您将精度设置为4,将模式设置为ROUND_HALF_EVEN,则解析"XX.X45"将始终产生"XX.X4",而"XX.X75"将始终产生"XX.X8"(最后一个{ {1}}将下一位数字四舍五入为偶数)。您还可以“量化”四舍五入到小数点后的 特定精度(因此您的精度可能为100,以允许在小数点的左手边和右手边组合100位数字,但是您可以相对于5进行量化,以将小数点的右手四舍五入到正好四位数)。

要点是,如果要在C / C ++中对表示实数中的数字的字符串进行精确的十进制舍入,请查看"0.0000"

对于您的特定用例,该代码的Python版本(使用mpdecimal package的原因是,像libmpdec这样的数字格式设置以避免科学记数是一件很麻烦的事情),其外观大致类似于:

"1.1E-26"

显然,等效的C ++代码会稍微复杂一些,但并不一定要复杂得多。 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='') 配方可以简化,从而避免处理大量我们不需要的金钱事物,并且如果您不需要处理科学计数法,则精度计算会更简单。无论如何,moneyfmt是Python 3.3+的libmpdec软件包的最终来源,因此可以做到所有 ,并保证符合IEEE 754十进制浮点规范。