Skip to content

Commit 6aea6d4

Browse files
committed
Use DECDIG=uint64_t if uint128_t is available
1 parent 34e4715 commit 6aea6d4

7 files changed

Lines changed: 111 additions & 44 deletions

File tree

.github/workflows/ci.yml

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ jobs:
2020

2121
host:
2222
needs: ruby-versions
23-
name: ${{ matrix.os }} ${{ matrix.ruby }}
23+
name: ${{ matrix.os }} ${{ matrix.ruby }} decdig_bits=${{ matrix.decdig_bits }}
2424
runs-on: ${{ matrix.os }}
2525
strategy:
2626
fail-fast: false
@@ -31,14 +31,18 @@ jobs:
3131
- macos-14
3232
- windows-latest
3333
ruby: ${{ fromJson(needs.ruby-versions.outputs.versions) }}
34+
decdig_bits: ['auto']
3435
include:
36+
- { os: ubuntu-latest, ruby: "4.0", decdig_bits: 32 }
37+
- { os: ubuntu-latest, ruby: "4.0", decdig_bits: 64 }
3538
- { os: windows-latest , ruby: mingw }
3639
- { os: windows-latest , ruby: mswin }
3740
exclude:
3841
- { os: windows-latest , ruby: debug }
3942
- { os: windows-latest , ruby: truffleruby }
4043
- { os: windows-latest , ruby: truffleruby-head }
4144
env:
45+
BIGDECIMAL_DECDIG_BITS: ${{ matrix.decdig_bits }}
4246
BIGDECIMAL_USE_VP_TEST_METHODS: true
4347
BUNDLE_WITHOUT: sig
4448

ext/bigdecimal/bigdecimal.c

Lines changed: 40 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3228,6 +3228,40 @@ BigDecimal_literal(const char *str)
32283228

32293229
#define BIGDECIMAL_LITERAL(var, val) (BIGDECIMAL_ ## var = BigDecimal_literal(#val))
32303230

3231+
#if SIZEOF_DECDIG == 4
3232+
# define ntt_multiply ntt_multiply32
3233+
#elif SIZEOF_DECDIG == 8 && BASE_FIG == 18
3234+
static void
3235+
ntt_multiply(size_t a_size, size_t b_size, uint64_t *a, uint64_t *b, uint64_t *c) {
3236+
size_t c_size = a_size + b_size;
3237+
BDVALUE bd_a = NewZeroWrap(1, a_size * BASE_FIG);
3238+
BDVALUE bd_b = NewZeroWrap(1, b_size * BASE_FIG);
3239+
BDVALUE bd_c = NewZeroWrap(1, c_size * BASE_FIG);
3240+
uint32_t *a32 = (uint32_t*)bd_a.real->frac;
3241+
uint32_t *b32 = (uint32_t*)bd_b.real->frac;
3242+
uint32_t *c32 = (uint32_t*)bd_c.real->frac;
3243+
3244+
// Pack to 64-bit (BASE_FIG=18) to 32-bit digits(BASE_FIG=9) and call ntt_multiply32
3245+
for (uint32_t i = 0; i < a_size; i++) {
3246+
uint64_t v = a[i];
3247+
a32[i * 2] = (uint32_t)(v / NTT_DECDIG_BASE);
3248+
a32[i * 2 + 1] = (uint32_t)(v % NTT_DECDIG_BASE);
3249+
}
3250+
for (uint32_t i = 0; i < b_size; i++) {
3251+
uint64_t v = b[i];
3252+
b32[i * 2] = (uint32_t)(v / NTT_DECDIG_BASE);
3253+
b32[i * 2 + 1] = (uint32_t)(v % NTT_DECDIG_BASE);
3254+
}
3255+
ntt_multiply32(a_size * 2, b_size * 2, a32, b32, c32);
3256+
for (uint32_t i = 0; i < c_size; i++) {
3257+
c[i] = (uint64_t)c32[i * 2] * NTT_DECDIG_BASE + c32[i * 2 + 1];
3258+
}
3259+
RB_GC_GUARD(bd_a.bigdecimal);
3260+
RB_GC_GUARD(bd_b.bigdecimal);
3261+
RB_GC_GUARD(bd_c.bigdecimal);
3262+
}
3263+
#endif
3264+
32313265
#ifdef BIGDECIMAL_USE_VP_TEST_METHODS
32323266
VALUE
32333267
BigDecimal_vpdivd_generic(VALUE self, VALUE r, VALUE cprec, void (*vpdivd_func)(Real*, Real*, Real*, Real*)) {
@@ -3486,13 +3520,15 @@ Init_bigdecimal(void)
34863520
rb_define_const(rb_cBigDecimal, "VERSION", rb_str_new2(BIGDECIMAL_VERSION));
34873521

34883522
/*
3489-
* Base value used in internal calculations. On a 32 bit system, BASE
3490-
* is 10000, indicating that calculation is done in groups of 4 digits.
3491-
* (If it were larger, BASE**2 wouldn't fit in 32 bits, so you couldn't
3523+
* Base value used in internal calculations.
3524+
* If uint128_t is available, BASE is (uint64_t)1000000000000000000ULL.
3525+
* Otherswise, BASE is 1000000000, indicating that calculation is done
3526+
* in groups of 9 digits.
3527+
* (If it were larger, BASE**2 wouldn't fit in 64 bits, so you couldn't
34923528
* guarantee that two groups could always be multiplied together without
34933529
* overflow.)
34943530
*/
3495-
rb_define_const(rb_cBigDecimal, "BASE", INT2FIX((SIGNED_VALUE)BASE));
3531+
rb_define_const(rb_cBigDecimal, "BASE", ULL2NUM(BASE));
34963532

34973533
/* Exceptions */
34983534

ext/bigdecimal/bigdecimal.h

Lines changed: 36 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -17,40 +17,50 @@
1717
# include <float.h>
1818
#endif
1919

20-
#define DECDIG uint32_t
21-
#define DECDIG_DBL uint64_t
22-
#define DECDIG_DBL_SIGNED int64_t
23-
#define SIZEOF_DECDIG 4
24-
#define PRI_DECDIG_PREFIX ""
25-
#ifdef PRI_LL_PREFIX
26-
# define PRI_DECDIG_DBL_PREFIX PRI_LL_PREFIX
27-
#else
28-
# define PRI_DECDIG_DBL_PREFIX "l"
20+
#ifndef BIGDECIMAL_DECDIG_BITS
21+
# ifdef HAVE_INT128_T
22+
# define BIGDECIMAL_DECDIG_BITS 64
23+
# else
24+
# define BIGDECIMAL_DECDIG_BITS 32
25+
# endif
26+
#endif
27+
28+
#if BIGDECIMAL_DECDIG_BITS == 64
29+
# define DECDIG uint64_t
30+
# define DECDIG_DBL uint128_t
31+
# define DECDIG_DBL_SIGNED int128_t
32+
# define SIZEOF_DECDIG 8
33+
# define PRIuDECDIG PRIu64
34+
#elif BIGDECIMAL_DECDIG_BITS == 32
35+
# define DECDIG uint32_t
36+
# define DECDIG_DBL uint64_t
37+
# define DECDIG_DBL_SIGNED int64_t
38+
# define SIZEOF_DECDIG 4
39+
# define PRIuDECDIG PRIu32
2940
#endif
3041

31-
#define PRIdDECDIG PRI_DECDIG_PREFIX"d"
32-
#define PRIiDECDIG PRI_DECDIG_PREFIX"i"
33-
#define PRIoDECDIG PRI_DECDIG_PREFIX"o"
34-
#define PRIuDECDIG PRI_DECDIG_PREFIX"u"
35-
#define PRIxDECDIG PRI_DECDIG_PREFIX"x"
36-
#define PRIXDECDIG PRI_DECDIG_PREFIX"X"
37-
38-
#define PRIdDECDIG_DBL PRI_DECDIG_DBL_PREFIX"d"
39-
#define PRIiDECDIG_DBL PRI_DECDIG_DBL_PREFIX"i"
40-
#define PRIoDECDIG_DBL PRI_DECDIG_DBL_PREFIX"o"
41-
#define PRIuDECDIG_DBL PRI_DECDIG_DBL_PREFIX"u"
42-
#define PRIxDECDIG_DBL PRI_DECDIG_DBL_PREFIX"x"
43-
#define PRIXDECDIG_DBL PRI_DECDIG_DBL_PREFIX"X"
44-
45-
#define BIGDECIMAL_BASE ((DECDIG)1000000000U)
46-
#define BIGDECIMAL_COMPONENT_FIGURES 9
42+
#if SIZEOF_DECDIG == 8
43+
# define BIGDECIMAL_BASE ((DECDIG)1000000000000000000ULL)
44+
# define BIGDECIMAL_COMPONENT_FIGURES 18
45+
/*
46+
* The number of components required for a 64-bit integer.
47+
*
48+
* INT64_MAX: 9_223372036854775807
49+
* UINT64_MAX: 18_446744073709551615
50+
*/
51+
# define BIGDECIMAL_INT64_MAX_LENGTH 2
52+
53+
#elif SIZEOF_DECDIG == 4
54+
# define BIGDECIMAL_BASE ((DECDIG)1000000000U)
55+
# define BIGDECIMAL_COMPONENT_FIGURES 9
4756
/*
4857
* The number of components required for a 64-bit integer.
4958
*
5059
* INT64_MAX: 9_223372036_854775807
5160
* UINT64_MAX: 18_446744073_709551615
5261
*/
53-
#define BIGDECIMAL_INT64_MAX_LENGTH 3
62+
# define BIGDECIMAL_INT64_MAX_LENGTH 3
63+
#endif
5464

5565
#define BIGDECIMAL_DOUBLE_FIGURES (1+DBL_DIG)
5666

ext/bigdecimal/extconf.rb

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,9 @@ def have_builtin_func(name, check_expr, opt = "", &b)
5252
bigdecimal_rb = "$(srcdir)/../../lib/bigdecimal.rb"
5353
end
5454

55+
decdig_bits = ENV['BIGDECIMAL_DECDIG_BITS']
56+
$defs.push("-DBIGDECIMAL_DECDIG_BITS=#{decdig_bits}") if %w[32 64].include?(decdig_bits)
57+
5558
$defs.push '-DBIGDECIMAL_USE_VP_TEST_METHODS' if ENV['BIGDECIMAL_USE_VP_TEST_METHODS'] == 'true'
5659

5760
create_makefile('bigdecimal') {|mf|

ext/bigdecimal/ntt.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -117,9 +117,9 @@ mod_restore_prime_24_26_29_shift_27(uint32_t mod1, uint32_t mod2, uint32_t mod3,
117117
* Uses three NTTs with mod (24 << 27 | 1), (26 << 27 | 1), and (29 << 27 | 1)
118118
*/
119119
static void
120-
ntt_multiply(size_t a_size, size_t b_size, uint32_t *a, uint32_t *b, uint32_t *c) {
120+
ntt_multiply32(size_t a_size, size_t b_size, uint32_t *a, uint32_t *b, uint32_t *c) {
121121
if (a_size < b_size) {
122-
ntt_multiply(b_size, a_size, b, a, c);
122+
ntt_multiply32(b_size, a_size, b, a, c);
123123
return;
124124
}
125125

test/bigdecimal/helper.rb

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,12 @@
55

66
module TestBigDecimalBase
77
BASE = BigDecimal::BASE
8-
BASE_FIG = 9
8+
case BASE
9+
when (_avoid_jruby_crash = 1000000000000000000)
10+
BASE_FIG = 18
11+
when 1000000000
12+
BASE_FIG = 9
13+
end
914

1015
def setup
1116
@mode = BigDecimal.mode(BigDecimal::EXCEPTION_ALL)

test/bigdecimal/test_vp_operation.rb

Lines changed: 19 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -121,12 +121,13 @@ def test_vpdivd_large_quotient_prec
121121
end
122122

123123
def test_vpdivd_with_one
124-
x = BigDecimal('1234.2468000001234')
125-
assert_vpdivd_equal([BigDecimal('1234'), BigDecimal('0.2468000001234')], [x, BigDecimal(1), 1])
126-
assert_vpdivd_equal([BigDecimal('+1234.2468'), BigDecimal('+0.1234e-9')], [+x, BigDecimal(+1), 2])
127-
assert_vpdivd_equal([BigDecimal('-1234.2468'), BigDecimal('+0.1234e-9')], [+x, BigDecimal(-1), 2])
128-
assert_vpdivd_equal([BigDecimal('-1234.2468'), BigDecimal('-0.1234e-9')], [-x, BigDecimal(+1), 2])
129-
assert_vpdivd_equal([BigDecimal('+1234.2468'), BigDecimal('-0.1234e-9')], [-x, BigDecimal(-1), 2])
124+
rest = BigDecimal("0.1234e-#{BASE_FIG}")
125+
x = BigDecimal('1234.2468') + rest
126+
assert_vpdivd_equal([BigDecimal('1234'), BigDecimal('0.2468') + rest], [x, BigDecimal(1), 1])
127+
assert_vpdivd_equal([BigDecimal('+1234.2468'), +rest], [+x, BigDecimal(+1), 2])
128+
assert_vpdivd_equal([BigDecimal('-1234.2468'), +rest], [+x, BigDecimal(-1), 2])
129+
assert_vpdivd_equal([BigDecimal('-1234.2468'), -rest], [-x, BigDecimal(+1), 2])
130+
assert_vpdivd_equal([BigDecimal('+1234.2468'), -rest], [-x, BigDecimal(-1), 2])
130131
end
131132

132133
def test_vpdivd_precisions
@@ -169,9 +170,17 @@ def test_vpdivd_large_prec_divisor
169170
end
170171

171172
def test_vpdivd_intermediate_zero
172-
x = BigDecimal('123456789.246913578000000000123456789')
173-
y = BigDecimal('123456789')
174-
assert_vpdivd_equal([BigDecimal('1.000000002000000000000000001'), BigDecimal(0)], [x, y, 4])
175-
assert_vpdivd_equal([BigDecimal('1.000000000049999999'), BigDecimal('1e-18')], [BigDecimal("2.000000000099999999"), 2, 3])
173+
case BASE_FIG
174+
when 9
175+
x = BigDecimal('123456789.246913578000000000123456789')
176+
y = BigDecimal('123456789')
177+
assert_vpdivd_equal([BigDecimal('1.000000002000000000000000001'), BigDecimal(0)], [x, y, 4])
178+
assert_vpdivd_equal([BigDecimal('1.000000000049999999'), BigDecimal('1e-18')], [BigDecimal("2.000000000099999999"), 2, 3])
179+
when 18
180+
x = BigDecimal('123456789.246913578000000000000000000000000000123456789')
181+
y = BigDecimal('123456789')
182+
assert_vpdivd_equal([BigDecimal('1.000000002000000000000000000000000000000000001'), BigDecimal(0)], [x, y, 4])
183+
assert_vpdivd_equal([BigDecimal('1.000000000000000000049999999999999999'), BigDecimal('1e-36')], [BigDecimal("2.000000000000000000099999999999999999"), 2, 3])
184+
end
176185
end
177186
end

0 commit comments

Comments
 (0)