NewFromFloatWithExponent converts a float64 to Decimal, with an arbitrary number of fractional digits. Example: NewFromFloatWithExponent(123.456, -2).String() // output: "123.46"
(value float64, exp int32)
| 375 | // |
| 376 | // NewFromFloatWithExponent(123.456, -2).String() // output: "123.46" |
| 377 | func NewFromFloatWithExponent(value float64, exp int32) Decimal { |
| 378 | if math.IsNaN(value) || math.IsInf(value, 0) { |
| 379 | panic(fmt.Sprintf("Cannot create a Decimal from %v", value)) |
| 380 | } |
| 381 | |
| 382 | bits := math.Float64bits(value) |
| 383 | mant := bits & (1<<52 - 1) |
| 384 | exp2 := int32((bits >> 52) & (1<<11 - 1)) |
| 385 | sign := bits >> 63 |
| 386 | |
| 387 | if exp2 == 0 { |
| 388 | // specials |
| 389 | if mant == 0 { |
| 390 | return Decimal{} |
| 391 | } |
| 392 | // subnormal |
| 393 | exp2++ |
| 394 | } else { |
| 395 | // normal |
| 396 | mant |= 1 << 52 |
| 397 | } |
| 398 | |
| 399 | exp2 -= 1023 + 52 |
| 400 | |
| 401 | // normalizing base-2 values |
| 402 | for mant&1 == 0 { |
| 403 | mant = mant >> 1 |
| 404 | exp2++ |
| 405 | } |
| 406 | |
| 407 | // maximum number of fractional base-10 digits to represent 2^N exactly cannot be more than -N if N<0 |
| 408 | if exp < 0 && exp < exp2 { |
| 409 | if exp2 < 0 { |
| 410 | exp = exp2 |
| 411 | } else { |
| 412 | exp = 0 |
| 413 | } |
| 414 | } |
| 415 | |
| 416 | // representing 10^M * 2^N as 5^M * 2^(M+N) |
| 417 | exp2 -= exp |
| 418 | |
| 419 | temp := big.NewInt(1) |
| 420 | dMant := big.NewInt(int64(mant)) |
| 421 | |
| 422 | // applying 5^M |
| 423 | if exp > 0 { |
| 424 | temp = temp.SetInt64(int64(exp)) |
| 425 | temp = temp.Exp(fiveInt, temp, nil) |
| 426 | } else if exp < 0 { |
| 427 | temp = temp.SetInt64(-int64(exp)) |
| 428 | temp = temp.Exp(fiveInt, temp, nil) |
| 429 | dMant = dMant.Mul(dMant, temp) |
| 430 | temp = temp.SetUint64(1) |
| 431 | } |
| 432 | |
| 433 | // applying 2^(M+N) |
| 434 | if exp2 > 0 { |
searching dependent graphs…