preciseNum.mjs

import get from 'lodash-es/get.js'
import isnum from './isnum.mjs'
import isint from './isint.mjs'
import isbol from './isbol.mjs'
import cstr from './cstr.mjs'
import dig from './dig.mjs'


/**
 * 轉數字成為原始精度之數字字串
 *
 * Unit Test: {@link https://github.com/yuda-lyu/wsemi/blob/master/test/preciseNum.test.mjs Github}
 * @memberOf wsemi
 * @param {String|Number} v 輸入數字字串或數字
 * @param {Object} [opt={}] 輸入設定物件,預設{}
 * @param {Boolean} [opt.returnDigit=false] 輸入是否回傳小數位數布林值,預設false
 * @returns {String} 回傳數字字串,若returnDigit=true則回傳小數位數整數
 * @example
 *
 * console.log(`preciseNum(0)`, preciseNum(0))
 * // => preciseNum(0) 0
 *
 * console.log(`preciseNum(1)`, preciseNum(1))
 * // => preciseNum(1) 1
 *
 * console.log(`preciseNum(0.3)`, preciseNum(0.3))
 * // => preciseNum(0.3) 0.3
 *
 * console.log(`preciseNum(0.1 + 0.2)`, preciseNum(0.1 + 0.2))
 * // => preciseNum(0.1 + 0.2) 0.3
 *
 * console.log(`preciseNum(4.67 + 7.12 + 94.4)`, preciseNum(4.67 + 7.12 + 94.4))
 * // => preciseNum(4.67 + 7.12 + 94.4) 106.19
 *
 * console.log(`preciseNum(94.4 + 7.12 + 4.67)`, preciseNum(94.4 + 7.12 + 4.67))
 * // => preciseNum(94.4 + 7.12 + 4.67) 106.19
 *
 * console.log(`preciseNum(0, { returnDigit: true })`, preciseNum(0, { returnDigit: true }))
 * // => preciseNum(0, { returnDigit: true })) 0
 *
 * console.log(`preciseNum(1, { returnDigit: true })`, preciseNum(1, { returnDigit: true }))
 * // => preciseNum(1, { returnDigit: true })) 0
 *
 * console.log(`preciseNum(0.3, { returnDigit: true })`, preciseNum(0.3, { returnDigit: true }))
 * // => preciseNum(0.3, { returnDigit: true })) 1
 *
 * console.log(`preciseNum(0.1 + 0.2, { returnDigit: true })`, preciseNum(0.1 + 0.2, { returnDigit: true }))
 * // => preciseNum(0.1 + 0.2, { returnDigit: true })) 1
 *
 * console.log(`preciseNum(4.67 + 7.12 + 94.4, { returnDigit: true })`, preciseNum(4.67 + 7.12 + 94.4, { returnDigit: true }))
 * // => preciseNum(4.67 + 7.12 + 94.4, { returnDigit: true })) 2
 *
 * console.log(`preciseNum(94.4 + 7.12 + 4.67, { returnDigit: true })`, preciseNum(94.4 + 7.12 + 4.67, { returnDigit: true }))
 * // => preciseNum(94.4 + 7.12 + 4.67, { returnDigit: true })) 2
 *
 */
function preciseNum(v, opt = {}) {

    //check
    if (!isnum(v)) {
        throw new Error(`v is not a number`)
    }

    //returnDigit
    let returnDigit = get(opt, 'returnDigit')
    if (!isbol(returnDigit)) {
        returnDigit = false
    }

    //check
    if (isint(v)) {
        if (returnDigit) {
            return 0
        }
        return cstr(v) //不能用cint, 得要回傳數字字串
    }

    //eps
    let eps = 1e-9

    //idig, vv
    let idig = null
    let vv = null
    for (let i = 1; i <= 16; i++) { //最高測試至16位

        //multiplier
        let multiplier = Math.pow(10, i)
        // console.log(i, multiplier)

        //multiplied
        let multiplied = v * multiplier

        //檢查乘以10的n次方是否與其四捨五入的值非常接近
        if (Math.abs(multiplied - Math.round(multiplied)) < eps) {
            idig = i
            vv = dig(v, i)
            break
        }
    }
    // console.log('vv', vv)

    //check, 若無法找到代表v精度超高, 直接轉字串回傳
    if (vv === null) {
        idig = 16
        vv = cstr(v)
    }

    if (returnDigit) {
        return idig
    }
    return vv
}


export default preciseNum