Created
January 27, 2021 01:51
-
-
Save axetroy/4aa6175198f61a40e1fd417f049dcfec to your computer and use it in GitHub Desktop.
Big Float
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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()) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment