|
| 1 | +# frozen_string_literal: false |
| 2 | +require_relative 'helper' |
| 3 | +require 'bigdecimal' |
| 4 | + |
| 5 | +class TestVpOperation < Test::Unit::TestCase |
| 6 | + include TestBigDecimalBase |
| 7 | + |
| 8 | + def setup |
| 9 | + super |
| 10 | + unless BigDecimal.instance_methods.include?(:vpdivd) |
| 11 | + # rake clean && BIGDECIMAL_USE_VP_TEST_METHODS=true rake compile |
| 12 | + omit 'Compile with BIGDECIMAL_USE_VP_TEST_METHODS=true to run this test' |
| 13 | + end |
| 14 | + end |
| 15 | + |
| 16 | + def test_vpmult |
| 17 | + assert_equal(BigDecimal('121932631112635269'), BigDecimal('123456789').vpmult(BigDecimal('987654321'))) |
| 18 | + assert_equal(BigDecimal('12193263.1112635269'), BigDecimal('123.456789').vpmult(BigDecimal('98765.4321'))) |
| 19 | + x = 123**456 |
| 20 | + y = 987**123 |
| 21 | + assert_equal(BigDecimal("#{x * y}e-300"), BigDecimal("#{x}e-100").vpmult(BigDecimal("#{y}e-200"))) |
| 22 | + end |
| 23 | + |
| 24 | + def test_vpdivd |
| 25 | + # a[0] > b[0] |
| 26 | + # XXXX_YYYY_ZZZZ / 1111 #=> 000X_000Y_000Z |
| 27 | + x1 = BigDecimal('2' * BASE_FIG + '3' * BASE_FIG + '4' * BASE_FIG + '5' * BASE_FIG + '6' * BASE_FIG) |
| 28 | + y = BigDecimal('1' * BASE_FIG) |
| 29 | + d1 = BigDecimal("2e#{BASE_FIG * 4}") |
| 30 | + d2 = BigDecimal("3e#{BASE_FIG * 3}") + d1 |
| 31 | + d3 = BigDecimal("4e#{BASE_FIG * 2}") + d2 |
| 32 | + d4 = BigDecimal("5e#{BASE_FIG}") + d3 |
| 33 | + d5 = BigDecimal(6) + d4 |
| 34 | + assert_equal([d1, x1 - d1 * y], x1.vpdivd(y, 1)) |
| 35 | + assert_equal([d2, x1 - d2 * y], x1.vpdivd(y, 2)) |
| 36 | + assert_equal([d3, x1 - d3 * y], x1.vpdivd(y, 3)) |
| 37 | + assert_equal([d4, x1 - d4 * y], x1.vpdivd(y, 4)) |
| 38 | + assert_equal([d5, x1 - d5 * y], x1.vpdivd(y, 5)) |
| 39 | + |
| 40 | + # a[0] < b[0] |
| 41 | + # 00XX_XXYY_YYZZ_ZZ00 / 1111 #=> 0000_0X00_0Y00_0Z00 |
| 42 | + shift = BASE_FIG / 2 |
| 43 | + x2 = BigDecimal('2' * BASE_FIG + '3' * BASE_FIG + '4' * BASE_FIG + '5' * BASE_FIG + '6' * BASE_FIG + '0' * shift) |
| 44 | + d1 = BigDecimal("2e#{4 * BASE_FIG + shift}") |
| 45 | + d2 = BigDecimal("3e#{3 * BASE_FIG + shift}") + d1 |
| 46 | + d3 = BigDecimal("4e#{2 * BASE_FIG + shift}") + d2 |
| 47 | + d4 = BigDecimal("5e#{BASE_FIG + shift}") + d3 |
| 48 | + d5 = BigDecimal("6e#{shift}") + d4 |
| 49 | + assert_equal([0, x2], x2.vpdivd(y, 1)) |
| 50 | + assert_equal([d1, x2 - d1 * y], x2.vpdivd(y, 2)) |
| 51 | + assert_equal([d2, x2 - d2 * y], x2.vpdivd(y, 3)) |
| 52 | + assert_equal([d3, x2 - d3 * y], x2.vpdivd(y, 4)) |
| 53 | + assert_equal([d4, x2 - d4 * y], x2.vpdivd(y, 5)) |
| 54 | + assert_equal([d5, x2 - d5 * y], x2.vpdivd(y, 6)) |
| 55 | + end |
| 56 | + |
| 57 | + def test_vpdivd_large_quotient_prec |
| 58 | + # 0001 / 0003 = 0000_3333_3333 |
| 59 | + assert_equal([BigDecimal('0.' + '3' * BASE_FIG * 9), BigDecimal("1e-#{9 * BASE_FIG}")], BigDecimal(1).vpdivd(BigDecimal(3), 10)) |
| 60 | + # 1000 / 0003 = 0333_3333_3333 |
| 61 | + assert_equal([BigDecimal('3' * (BASE_FIG - 1) + '.' + '3' * BASE_FIG * 9), BigDecimal("1e-#{9 * BASE_FIG}")], BigDecimal(BASE / 10).vpdivd(BigDecimal(3), 10)) |
| 62 | + end |
| 63 | + |
| 64 | + def test_vpdivd_with_one |
| 65 | + x = BigDecimal('1234.2468000001234') |
| 66 | + assert_equal([BigDecimal('1234'), BigDecimal('0.2468000001234')], x.vpdivd(BigDecimal(1), 1)) |
| 67 | + assert_equal([BigDecimal('+1234.2468'), BigDecimal('+0.1234e-9')], (+x).vpdivd(BigDecimal(+1), 2)) |
| 68 | + assert_equal([BigDecimal('-1234.2468'), BigDecimal('+0.1234e-9')], (+x).vpdivd(BigDecimal(-1), 2)) |
| 69 | + assert_equal([BigDecimal('-1234.2468'), BigDecimal('-0.1234e-9')], (-x).vpdivd(BigDecimal(+1), 2)) |
| 70 | + assert_equal([BigDecimal('+1234.2468'), BigDecimal('-0.1234e-9')], (-x).vpdivd(BigDecimal(-1), 2)) |
| 71 | + end |
| 72 | + |
| 73 | + def test_vpdivd_precisions |
| 74 | + xs = [5, 10, 20, 40].map {|n| 123 ** n } |
| 75 | + ys = [5, 10, 20, 40].map {|n| 321 ** n } |
| 76 | + xs.product(ys).each do |x, y| |
| 77 | + [1, 2, 10, 20].each do |n| |
| 78 | + xn = (x.digits.size + BASE_FIG - 1) / BASE_FIG |
| 79 | + yn = (y.digits.size + BASE_FIG - 1) / BASE_FIG |
| 80 | + base = BASE ** (n - xn + yn - 1) |
| 81 | + div = BigDecimal((x * base / y).to_i) / base |
| 82 | + assert_equal([div, x - y * div], BigDecimal(x).vpdivd(y, n)) |
| 83 | + end |
| 84 | + end |
| 85 | + end |
| 86 | + |
| 87 | + def test_vpdivd_carry_borrow |
| 88 | + y_small = BASE / 7 * BASE ** 4 |
| 89 | + y_large = (4 * BASE_FIG).times.map {|i| i % 9 + 1 }.join.to_i |
| 90 | + [y_large, y_small].each do |y| |
| 91 | + [0, 1, 2, BASE - 2, BASE - 1].repeated_permutation(4) do |a, b, c, d| |
| 92 | + x = y * (3 * BASE**4 + a * BASE**3 + b * BASE**2 + c * BASE + d) / BASE |
| 93 | + div = BigDecimal(x * BASE / y) / BASE |
| 94 | + mod = BigDecimal(x) - div * y |
| 95 | + assert_equal([div, mod], BigDecimal(x).vpdivd(BigDecimal(y), 5)) |
| 96 | + end |
| 97 | + end |
| 98 | + end |
| 99 | + |
| 100 | + def test_vpdivd_large_prec_divisor |
| 101 | + x = BigDecimal('2468.000000000000000000000000003') |
| 102 | + y1 = BigDecimal('1234.000000000000000000000000001') |
| 103 | + y2 = BigDecimal('1234.000000000000000000000000004') |
| 104 | + divy1_1 = BigDecimal(2) |
| 105 | + divy2_1 = BigDecimal(1) |
| 106 | + divy2_2 = BigDecimal('1.' + '9' * BASE_FIG) |
| 107 | + assert_equal([divy1_1, x - y1 * divy1_1], x.vpdivd(y1, 1)) |
| 108 | + assert_equal([divy2_1, x - y2 * divy2_1], x.vpdivd(y2, 1)) |
| 109 | + assert_equal([divy2_2, x - y2 * divy2_2], x.vpdivd(y2, 2)) |
| 110 | + end |
| 111 | + |
| 112 | + def test_vpdivd_intermediate_zero |
| 113 | + if BASE_FIG == 9 |
| 114 | + x = BigDecimal('123456789.246913578000000000123456789') |
| 115 | + y = BigDecimal('123456789') |
| 116 | + assert_equal([BigDecimal('1.000000002000000000000000001'), BigDecimal(0)], x.vpdivd(y, 4)) |
| 117 | + assert_equal([BigDecimal('1.000000000049999999'), BigDecimal('1e-18')], BigDecimal("2.000000000099999999").vpdivd(2, 3)) |
| 118 | + else |
| 119 | + x = BigDecimal('1234.246800001234') |
| 120 | + y = BigDecimal('1234') |
| 121 | + assert_equal([BigDecimal('1.000200000001'), BigDecimal(0)], x.vpdivd(y, 4)) |
| 122 | + assert_equal([BigDecimal('1.00000499'), BigDecimal('1e-8')], BigDecimal("2.00000999").vpdivd(2, 3)) |
| 123 | + end |
| 124 | + end |
| 125 | +end |
0 commit comments