JS: 数千の金額が分割され、小数点以下 2 桁が保持 (四捨五入) - 正規/非正規

あなたが作成したメソッドが次のパラメータのテストに合格できる場合は、この記事をスキップしてください。

f(null);       // invalid value
f(undefined);  // invalid value
f();           // invalid value
f([12.888]);   // invalid value
f('abc')       // invalid value
f(NaN)         // invalid value
f(0.1+0.2);    // 0.30
f(0.3 - 0.2);  // 0.10
f(1e3);        // 1,000.00
f('1e3')       // 1,000.00
f(123456)      // 123,456.00
f(123456.456)  // 123,456.46
f(12.899)      // 12.90
f(12.999)      // 13.00
f(10.055)      // 10.06
f(10.005)      // 10.01
f(10.105)      // 10.11
f(10.155);     // 10.16
f(10.105)      // 10.11
f(0.0001)      // 0.00
f(-10.105)     // -10.11
f(.5)          // 0.50
f(0/0)         // invalid value
f(12/0)        // invalid value
f(10 ** -4)    // 0.00

それがうまくいかない場合は、以下を参照してください。

1: 方法の詳細な説明

アイデア:

  • パラメータは文字列と数値形式 (負の数をサポート) のみをサポートしており、その他の形式はまだサポートされていません。
  • パラメータは小数点以下第 2 位までに四捨五入されます。
  • パラメータの整数の1000の位に区切り文字(,)が付加され、小数点以下2桁未満の末尾は0で埋められます。

1. パラメータは数値のみをサポートします

学生の中には、最初に .toString() をパラメータ化することを好む人もいるので、焦らないでください。

パラメータが null/未定義の場合、バックグラウンドによってパラメータが返されることがあります。もちろん、エラー報告も静かに待っています。

[12.888] を再度サイレントに渡し、配列が toString メソッドをカスタマイズし、結果は「12.888」を返しました。この時点では、プログラムは正常に実行できます。

したがって、パラメータは数値のみをサポートし、残りは直接「無効な値」を返すことに同意しましょう。この数値は数値型と文字列型に限定されますが、同時にisFinite (パラメーター) は true を返すことができます (そのため、あらゆる種類の付加機能を修正できます)。

isFinite は、最初にパラメーターを暗黙的に数値に変換します。NaN、Infinity、-Infinity をフィルターで除外します。

isFinite(Infinity)     // false
isFinite(-Infinity)    // false
isFinite(NaN)          // false
isFinite(undefined)    // false

isFinite(null)         // true
isFinite(2)            // true
isFinite(-2)           // true
isFinite(.5)           // true
isFinite(1e3)          // true

isFinite([1])          // true
isFinite([1,2])        // false
isFinite({})           // false
isFinite(new Date())   // true
isFinite(/x/)          // false

Number.isFinite() も使用できますが、パラメータを手動で数値に変換する必要があります。

最初はプランパラメータから変換した値がNaNでなければ良かったのですが、結果を検証するとIn,fin,ity.00というおかしな値が出ていました。それは自分自身で地雷を除去する方法でもあります。したがって、isFinite を思い切って使用してください。

したがって、この最初のステップは次のようになります。

function numberWithCommas(x, num = 2) {
  // 以下两个方法都可以过滤NaN 和 Infinity/-Infinity,任选其一
  let bool = isFinite(x);                     // 方法一
  // let bool = Number.isFinite(Number(x));   // 方法二
  if ((typeof x === 'string' || typeof x === 'number')
    && bool) {
    return addCommas(round(x, num), num)
  } else {
    return "invalid value"
  }
}

2. パラメータは小数点以下第 2 位までに四捨五入されます。

2桁まで四捨五入して、「できる!」と手を挙げた生徒もいました。to固定メソッド。もちろん、この答えを言った後は、そうはなりません。

さあ、さあ、栗を持って説明してください。

// 结果挺正常
(10).toFixed(2)         // "10.00"
10.005.toFixed(2)       // "10.01"

// 结果就挺不正常
(10.055).toFixed(2)     // "10.05"
(10.135).toFixed(2)     // "10.13"

したがって、toFixed() はあきらめてください。

  • 方法1:手書きラウンド法、
  • 方法 2: 巨人の肩の上に立つ (ここでは数値精度を使用する予定)

手書きの丸めメソッドでは、まず 100 を掛けて (カスタム回メソッド)、四捨五入し (Math.round())、次に 100 で割ります。

  • パラメーターは 100 倍され、times メソッドがカスタマイズされます。数学的な計算(パラメータ * 100)を直接使用しない理由は、js では浮動小数点数の計算が不正確すぎるためです。
10.155*100         // 1015.4999999999999
10**-4             // 0.00009999999999999999
Math.pow(10,-4)    // 0.00009999999999999999
0.1+0.2            // 0.30000000000000004
0.3-0.2            // 0.09999999999999998
  • Math.round は正の数に非常に適していますが、パラメータが負の数の場合は問題が発生する可能性があります。
console.log(Math.round(1.1))     // 1
console.log(Math.round(1.5))     // 2
console.log(Math.round(1.6))     // 2

console.log(Math.round(-1.1))    // -1
console.log(Math.round(-1.5))    // -1
console.log(Math.round(-1.6))    // -2

したがって、最初にパラメータの絶対値を取得し、計算を完了してから、(負の数の場合) 符号を復元します。

したがって、2 番目のステップでは、以下のラウンド方法のいずれかを選択します。

最初の方法 (NP) - 推奨

// 安装 number-precision
npm install number-precision --save

// 使用
import NP from 'number-precision';
// 或
const NP = require('number-precision')


function round(num, decimal = 2) {
  return NP.round(num, decimal)
}

 2番目の方法(カスタマイズされたラウンド方法、NPのロープロファイルバージョン)

function round(num, decimal = 2) {
  let base = Math.pow(10, decimal);
  let result = Math.round(Math.abs(times(num, base))) / base;
  if (num < 0 && result !== 0) {
    result *= -1;
  }
  return result;
}

function times (num1, num2) {
  const {val: val1, len: len1} = farmatVal(num1)
  const {val: val2, len: len2} = farmatVal(num2)
  return val1 * val2 / Math.pow(10, len1 + len2);
}

function farmatVal (num) {
  // floatNoDot:浮点数去掉小数点
  const floatNoDot = num => Number((num + '').replace('.', ''));
  // decLength:浮点数小数的位数
  const decLength = num => (((num + '').split('.'))[1] || '').length;
  return {
    val: floatNoDot(num),
    len: decLength(num)
  }
}

3. フォーマットして返します。整数に千の位の区切り文字を追加し、小数点以下 2 桁未満の末尾に 0 を追加します。

ついにメインディッシュが来ました。1000 分の 1 の区切りは、正規化する最も便利で簡潔な方法です。

しかし、私は自分自身に問いかけなければなりません、私はルールを守ることができるでしょうか?そうしますか?そうしますか?これは・・・あまり良くないです、分かりやすいですが、ちょっと難しいと読む範囲ではありません。

この 3 番目のステップでは、以下の addCommas メソッドのいずれかを選択できます。もちろん、書式設定方法を書くのが得意な方には、ここで私がペンを差し上げます。

最初の方法(通常)

function addCommas(x, num = 2) {
  let [integer, decimals = ''] = (x + '').split('.')

  // 添加千分位分隔符
  integer = integer + ''
  let pattern = /(-?\d+)(\d{3})/;
  while (pattern.test(integer)) {
    integer = integer.replace(pattern, '$1,$2')
  }

  // 尾部补零
  decimals = (decimals + '0'.repeat(num)).slice(0, num)
  return integer + '.' + decimals;
}

2 番目の方法 (通常)

function addCommas(x, num = 2) {
  // 尾部补零
  x = x + ''
  x = x.replace(/^(-?\d+)$/, '$1.')
  let reg = new RegExp(`(\\.\\d{${num}})\\d*$`)
  x = (x + '0'.repeat(num)).replace(reg, '$1')

  // 添加分隔符
  x = x.replace('.', ',')
  let pattern = /(\d)(\d{3},)/;
  while (pattern.test(x)) {
    x = x.replace(pattern, '$1,$2')
  }

  let regDec = new RegExp(`,(\\d{${num}})$`)
  x = x.replace(regDec, '.$1')
  return x;
}

3 番目の方法 (非正規): 整数配列の 1,000 桁ごとに区切り文字を追加し、それを文字列に変換します。

function addCommas(x, num = 2) {
  // 符号位
  let sign = x < 0 ? '-' : '';

  let [
    integer = '',
    decimals = ''
  ] = (Math.abs(x).toString()).split('.');

  // 整数位
  let integerArr = [...integer];
  for (let len = integerArr.length, i = len - 1; i > 0; i--) {
    if ((len - 1 - i) % 3 === 2) {
      integerArr.splice(i, 0, ',')
    }
  }
  // 小数位补零
  decimals = decimals.slice(0, num).padEnd(num, '0')

  return sign + integerArr.join('') + '.' + decimals;
}

4番目の方法(非正規): 配列のreduceRightメソッドを使用してプロセスを蓄積します。

function addCommas(x, num = 2) {
  let sign = x < 0 ? '-' : '';

  let [
    integer = '',
    decimals = ''
  ] = (Math.abs(x).toString()).split('.');

  // 整数位
  let integerStr = ([...integer]).reduceRight((result, int, index, arr) => {
    return int + ((arr.length - 1 - index) % 3 === 0 ? ',': '') + result
  })
  // 小数位补零
  decimals = (decimals + '0'.repeat(num)).slice(0, num);
  return sign + integerStr + '.' + decimals;
}

2: メソッドの検証

console.log(numberWithCommas(null));         // invalid value
console.log(numberWithCommas(undefined));    // invalid value
console.log(numberWithCommas());             // invalid value
console.log(numberWithCommas([12.888]));     // invalid value
console.log(numberWithCommas('abc'));        // invalid value
console.log(numberWithCommas(NaN));          // invalid value
console.log(numberWithCommas(0.1 + 0.2));    // 0.30
console.log(numberWithCommas(0.3 - 0.2));    // 0.10
console.log(numberWithCommas(1e3));          // 1,000.00
console.log(numberWithCommas('1e3'));        // 1,000.00
console.log(numberWithCommas(123456));       // 123,456.00
console.log(numberWithCommas(123456.456));   // 123,456.46
console.log(numberWithCommas(12.899));       // 12.90
console.log(numberWithCommas(12.999));       // 13.00
console.log(numberWithCommas(10.055));       // 10.06
console.log(numberWithCommas(10.005));       // 10.01
console.log(numberWithCommas(10.105));       // 10.11
console.log(numberWithCommas(10.155));       // 10.16
console.log(numberWithCommas(-10.105));      // -10.11
console.log(numberWithCommas(.5));           // 0.50
console.log(numberWithCommas(0/0));          // invalid value
console.log(numberWithCommas(12/0));         // invalid value
console.log(numberWithCommas(10 ** -4))      // 0.00

基本的に要件は満たされていました。ただ問題は、JS言語の精度が2進数53桁までしかなく、絶対値が2の53乗以下の整数、つまり正確に表現できる整数でないと精度が保てないこと-2^{53}です2^{53}2 の 53 乗は 16 桁の 10 進数値であるため、JavaScript は 15 桁の 10 進数値を正確に処理できます。整数の数字に小数点以下 2 桁を加えた数字が 15 桁を超える場合、結果は不正確になる可能性があります。

次に、金額を小数点以下 2 桁にフォーマットするのは日常的な操作です。ただし、違約金利息などの一部の値については、小数点以下 3 桁の書式設定要件がある場合があります。この記事で説明する書式設定方法は、小数点以下 3 桁の処理を満たしています。

終わり。

おすすめ

転載: blog.csdn.net/weixin_43932309/article/details/128334277