如何将 JavaScript 中的数字除以任意精度(例如小数点后 28 位)

2024-04-05

我知道https://floating-point-gui.de/ https://floating-point-gui.de/事实上,有许多库可以帮助处理大数,但令人惊讶的是,我找不到任何可以处理除法运算结果中小数点后 19 位以上的库。

我花了几个小时尝试诸如精确数学 https://www.npmjs.com/package/exact-math, 小数.js https://github.com/MikeMcl/decimal.js, 大数.js https://github.com/MikeMcl/bignumber.js, 和别的。

你会如何处理下面标有⭐的情况?

// https://jestjs.io/docs/getting-started#using-typescript

import exactMath from 'exact-math'; // https://www.npmjs.com/package/exact-math
import { Decimal } from 'decimal.js'; // https://github.com/MikeMcl/decimal.js

const testCases = [
  // The following cases work in exact-math but fail in Decimal.js:
  '9999513263875304671192000009',
  '4513263875304671192000009',
  '530467119.530467119',
  // The following cases fail in both Decimal.js and exact-math:
  '1.1998679030467029262556391239', // ⭐ exact-math rounds these 28 decimal places to 17: "1.1998679030467029263000000000"
];

describe('decimals.js', () => {
  testCases.forEach((testCase) => {
    test(testCase, () => {
      expect(new Decimal(testCase).div(new Decimal(1)).toFixed(28)).toBe(testCase); // Dividing by 1 (very simple!)
    });
  });
});

describe('exact-math', () => {
  testCases.forEach((testCase) => {
    test(testCase, () => {
      expect(exactMath.div(testCase, 1, { returnString: true })).toBe(testCase); // Dividing by 1 (very simple!)
    });
  });
});


上面的一些测试用例没有意义(因为我不应该期望输出等于输入,因为我使用的是.toFixed().

然后真正的答案是建议 https://stackoverflow.com/questions/73832451/how-to-divide-numbers-in-javascript-to-arbitrary-precision-e-g-28-decimal-plac#comment130371861_73832451通过@James:使用maxDecimal选项:https://www.npmjs.com/package/exact-math#the-config-maxdecimal-property-usage https://www.npmjs.com/package/exact-math#the-config-maxdecimal-property-usage Or https://mikemcl.github.io/decimal.js/# precision https://mikemcl.github.io/decimal.js/#precision在decimal.js中。

请参阅下面带有 ⭐ 的行。

import exactMath from 'exact-math'; // https://www.npmjs.com/package/exact-math
import { Decimal } from 'decimal.js'; // https://github.com/MikeMcl/decimal.js

/**
 *
 * @param amount {string}
 * @param decimals {number} e.g. 6 would return 6 decimal places like 0.000000
 * @param locale {string} e.g. 'en-US' or 'de-DE'
 * @returns {string} e.g. 1,000.000000
 */
export function getLocaleStringToDecimals(amount: string, decimals: any, locale?: string): string {
  // Thanks to https://stackoverflow.com/a/68906367/ because https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/toLocaleString and https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/BigInt/toLocaleString would not work for huge numbers or numbers with many decimal places.

  const decimalFormat = new Intl.NumberFormat(locale, { minimumFractionDigits: 1, maximumFractionDigits: 1 });
  const decimalFullString = '1.1';
  const decimalFullNumber = Number.parseFloat(decimalFullString);
  const decimalChar = decimalFormat.format(decimalFullNumber).charAt(1); // e.g. '.' or ','
  const fixed = new Decimal(amount).toFixed(decimals);
  const [mainString, decimalString] = fixed.split('.'); // ['321321321321321321', '357' | '998']
  const mainFormat = new Intl.NumberFormat(locale, { minimumFractionDigits: 0 });
  let mainBigInt = BigInt(mainString); // 321321321321321321n
  const mainFinal = mainFormat.format(mainBigInt); // '321.321.321.321.321.321' | '321.321.321.321.321.322'
  const decimalFinal = typeof decimalString !== 'undefined' ? `${decimalChar}${decimalString}` : ''; // '.357' | '.998'
  const amountFinal = `${mainFinal}${decimalFinal}`; // '321.321.321.321.321.321,36' | '321.321.321.321.321.322,00'
  // console.log({
  //   amount,
  //   fixed,
  //   mainString,
  //   decimalString,
  //   'decimalString.length': decimalString ? decimalString.length : undefined,
  //   decimalFormat,
  //   decimalFinal,
  //   mainFormat,
  //   mainBigInt,
  //   mainFinal,
  //   amountFinal,
  // });
  return amountFinal;
}

/**
 *
 * @param amount {string}
 * @param decimals {number} e.g. 6 would return 6 decimal places like 0.000000
 * @param divisorPower {number} e.g. 0 for yocto, 24 for [base], 27 for kilo, etc 
 * @param locale {string} e.g. 'en-US' or 'de-DE'
 * @returns {string} e.g. 1,000.000000
 */
export function round(amount: string, decimals = 0, divisorPower = 0, locale?: string): string {
  if (divisorPower < 0) {
    throw new Error('divisorPower must be >= 0');
  }
  const amountCleaned = amount.replaceAll('_', '');
  const divisor = Math.pow(10, divisorPower);
  const value: string = exactMath.div(amountCleaned, divisor, { returnString: true, maxDecimal: amount.length + decimals }); // ⭐ https://www.npmjs.com/package/exact-math#the-config-maxdecimal-property-usage
  // console.log(`round(${amount}, decimals = ${decimals}, divisorPower = ${divisorPower}) = ${value}`, divisor);
  const localeString = getLocaleStringToDecimals(value, decimals, locale);
  return localeString;
}


我的测试用例现在通过了。谢谢!

附:看https://stackoverflow.com/a/68906367/ https://stackoverflow.com/a/68906367/是什么启发了我的代码。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何将 JavaScript 中的数字除以任意精度(例如小数点后 28 位) 的相关文章

  • jQuery 中的 Javascript .files[0] 属性

    jQuery 中是否有与此语句等效的语句 var value document getElementById id files 0 使用附加 files 0 的标准 jQuery 选择器似乎不起作用 并且我找不到与 files 等效的 jQ
  • 使用 Javascript 在 Imacros 中循环

    我如何使用 javascript 循环 imm imacros 脚本 我搜索了一下 发现了这个 for i 0 i lt n i iimPlay marconame iim 但当我使用它时 我的浏览器 Firefox 18 挂起 for i
  • 如何将中间件绑定到socket.io中的事件

    现在您可以将中间件绑定到io use middleware 但这仅在建立套接字连接时触发 有没有办法在将其传递给事件句柄之前拦截它 就像在expressjs中一样 换句话说 In 快递 js你可以做 app get middleware1
  • 为什么 jQuery 点击事件会多次触发

    我这里有这个示例代码http jsfiddle net DBBUL 10 http jsfiddle net DBBUL 10 document ready function creategene click function confir
  • 将一个文本框的内容复制到另一个文本框

    假设在文本框中输入了一个条目 是否可以在第二个文本框中保留相同的输入文本 如果是这样 这是如何完成的
  • Typescript 函数返回类型取决于参数的数量或类型

    假设我有一个函数 它应该根据参数的数量和类型返回不同的类型 我该如何在 TypeScript 中描述这一点 function foo t number string function foo t number s string boolea
  • 将 jquery-mobile 与 Webpack 结合使用

    我正在尝试使用 webpack 加载 jquery mobile 但到目前为止还没有运气 我知道 jquery mobile 依赖于 jquery ui 而 jquery ui 又依赖于 jquery 如何在 Webpack 中设置这样的场
  • 何时不使用承诺[关闭]

    Closed 这个问题是基于意见的 help closed questions 目前不接受答案 在阅读了数十篇关于 es6 Promise 有多伟大以及为什么我们应该实现它们的文章之后 我有这样的感觉 ALL我的 不平凡的 JavaScri
  • 创建 Cookie 时需要帮助

    我有一个名为yes和另一个名叫no
  • 在 MVC Razor 中的 C# 和 Javascript 之间共享常量

    我想在服务器上的 C 和客户端上的 Javascript 中都使用字符串常量 我将常量封装在 C 类中 namespace MyModel public static class Constants public const string
  • 保存/导出Chrome的JavaScript控制台输入历史记录

    无论如何 我可以保存或导出 JavaScript 控制台的历史记录吗 input 控制台历史记录 在 Google Chrome 中 我不想保存输出或错误 因此将鼠标悬停在控制台框上 右键单击并选择Save as 不是解决方案 我不想每次都
  • 用数组反向查找对象

    假设我有一个这样的对象 resourceMap a 0 1 2 3 4 5 6 7 8 9 10 b 11 12 c 21 23 d 54 55 56 57 510 确定是否的最佳方法是什么resourceId 21将会 c 我们不知道钥匙
  • jQuery 选择器:为什么 $("#id").find("p") 比 $("#id p") 更快

    该页面的作者 http 24ways org 2011 your jquery now with less suck http 24ways org 2011 your jquery now with less suck断言 jQuery
  • 如何滚动到div内的元素?

    我有一个滚动的div我想在点击它时发生一个事件 它会强制执行此操作div滚动以查看内部元素 我写的JavasCript是这样的 document getElementById chr scrollIntoView true 但这会在滚动时滚
  • 装饰器可以更改方法的签名吗?

    考虑一个函数 function handleFoo foo number 我想要一个解析 foo 的装饰器 例如 fetchFromApi foo function handleFoo foo number where fetchFromA
  • Jquery,清除/清空 tbody 元素的所有内容?

    我认为这会相当简单 但似乎空方法无法清除我拥有的 tbody 如果有人知道执行此操作的正确方法 我将不胜感激 我只想删除 tbody 中包含的所有内容 到目前为止我正在尝试 tbodyid empty HTML table tbody tr
  • ng-model 和值组合不适用于输入文本框

    我有两个输入文本框 我需要组合在两个文本框中输入的值并将其显示在第三个文本框中 如果我只使用value在第三个文本框中 Box 1
  • 替换两个引号之间的字符串

    我想转动一根绳子str hello my name is michael what s your s into hello my name is span class name michael span 我怎样才能在 JavaScript
  • Django 与谷歌图表

    我试图让谷歌图表显示在我的页面上 但我不知道如何将值从 django 视图传递到 javascript 以便我可以绘制图表 姜戈代码 array Year Sales Expenses 2004 1000 400 2005 1170 460
  • 如何在 SVG 元素上使用箭头标记?

    我需要在 d3 js 中创建一个箭头 但我找到的只是带有节点图的示例 我需要的是简单地制作一个从 A 点到 B 点的箭头 我尝试实现以下示例中的部分代码 http bl ocks org 1153292 http bl ocks org 1

随机推荐