Big Float

BigFloat.ts
复制

type Numeric = number | string | BigInt

function getType(o: unknown): string {
  const matcher = Object.prototype.toString.call(o).match(/\s(\w+)/)

  if (!matcher) {
    return ''
  }

  return matcher[1]
}

class BigFloat {
  private base!: BigInt
  private digit = 0
  constructor(base: Numeric, d?: number) {
    const [int, digit] = BigFloat.number2BigInt(base)

    this.base = int
    if (d !== undefined) {
      this.digit = d
    } else {
      this.digit = digit
    }
  }
  public plus(n: Numeric): BigFloat {
    const [int, digit] = BigFloat.number2BigInt(n)

    const maxDigit = Math.max(this.digit, digit)

    const base = BigInt(this.base.toString() + '0'.repeat(maxDigit - this.digit))
    const target = BigInt(int.toString() + '0'.repeat(maxDigit - digit))

    return new BigFloat(base + target, maxDigit)
  }

  public times(n: Numeric): BigFloat {
    const [int, digit] = BigFloat.number2BigInt(n)

    const maxDigit = Math.max(this.digit, digit)

    const base = BigInt(this.base.toString() + '0'.repeat(maxDigit - this.digit))
    const target = BigInt(int.toString() + '0'.repeat(maxDigit - digit))

    return new BigFloat(base * target, Math.pow(maxDigit, 2))
  }

  public toString(): string {
    const str = this.base.toString()

    const dotPosition = str.length - this.digit

    let result = str.slice(0, dotPosition).concat('.').concat(str.slice(dotPosition))

    if (dotPosition === 0) {
      result = '0' + result
    }

    if (this.digit > 0) {
      result = result.replace(/0+$/, '')
      result = result.replace(/\.$/, '')
    }

    return result
  }

  private static number2BigInt(num: unknown): [BigInt, number] {
    const type = getType(num)

    if (type === 'BigInt') {
      return [num as BigInt, 0]
    } else if (type === 'Number') {
      const numString = (num as number).toString()

      // float
      const dotIndex = numString.indexOf('.')

      // if float64
      if (dotIndex >= 0) {
        const digit = numString.length - dotIndex - 1
        const numArr = numString.split('')

        const intString = numArr
          .slice(0, dotIndex)
          .concat(numArr.slice(dotIndex + 1))
          .join('')
          .replace(/^0+/, '')

        return [BigInt(intString), digit]
      } else {
        // if int
        return [BigInt(num), 0]
      }
    } else if (type === 'String') {
      const numString = num as string

      if (/^\d+(\.\d+)?$/.test(numString)) {
        if (/^\d+$/.test(numString)) {
          return [BigInt(num), 0]
        } else {
          // if float
          const dotIndex = numString.indexOf('.')
          const digit = numString.length - dotIndex - 1
          const numArr = numString.split('')

          const intString = numArr
            .slice(0, dotIndex)
            .concat(numArr.slice(dotIndex + 1))
            .join('')
            .replace(/^0+/, '')

          return [BigInt(intString), digit]
        }
      } else {
        throw new TypeError(`invalid number '${num}'`)
      }
    } else {
      throw new TypeError(`invalid number '${num}'`)
    }
  }
}

console.log(new BigFloat(0.1).plus(0.2333).toString())
console.log(new BigFloat(0.123456789).plus(0.987654321).toString())
console.log(new BigFloat('123.93323123123123123123990844').plus('0.123409212333333123123').toString())
console.log(new BigFloat('0.123').times('0.321').toString())

大牛们的评论:朕有话说

还没有人评论哦,赶紧抢沙发!