@@ -551,6 +551,8 @@ static void div_var(const NumericVar *var1, const NumericVar *var2,
551
551
int rscale , bool round );
552
552
static void div_var_fast (const NumericVar * var1 , const NumericVar * var2 ,
553
553
NumericVar * result , int rscale , bool round );
554
+ static void div_var_int (const NumericVar * var , int ival , int ival_weight ,
555
+ NumericVar * result , int rscale , bool round );
554
556
static int select_div_scale (const NumericVar * var1 , const NumericVar * var2 );
555
557
static void mod_var (const NumericVar * var1 , const NumericVar * var2 ,
556
558
NumericVar * result );
@@ -8451,8 +8453,33 @@ div_var(const NumericVar *var1, const NumericVar *var2, NumericVar *result,
8451
8453
errmsg ("division by zero" )));
8452
8454
8453
8455
/*
8454
- * Now result zero check
8456
+ * If the divisor has just one or two digits, delegate to div_var_int(),
8457
+ * which uses fast short division.
8455
8458
*/
8459
+ if (var2ndigits <= 2 )
8460
+ {
8461
+ int idivisor ;
8462
+ int idivisor_weight ;
8463
+
8464
+ idivisor = var2 -> digits [0 ];
8465
+ idivisor_weight = var2 -> weight ;
8466
+ if (var2ndigits == 2 )
8467
+ {
8468
+ idivisor = idivisor * NBASE + var2 -> digits [1 ];
8469
+ idivisor_weight -- ;
8470
+ }
8471
+ if (var2 -> sign == NUMERIC_NEG )
8472
+ idivisor = - idivisor ;
8473
+
8474
+ div_var_int (var1 , idivisor , idivisor_weight , result , rscale , round );
8475
+ return ;
8476
+ }
8477
+
8478
+ /*
8479
+ * Otherwise, perform full long division.
8480
+ */
8481
+
8482
+ /* Result zero check */
8456
8483
if (var1ndigits == 0 )
8457
8484
{
8458
8485
zero_var (result );
@@ -8510,23 +8537,6 @@ div_var(const NumericVar *var1, const NumericVar *var2, NumericVar *result,
8510
8537
alloc_var (result , res_ndigits );
8511
8538
res_digits = result -> digits ;
8512
8539
8513
- if (var2ndigits == 1 )
8514
- {
8515
- /*
8516
- * If there's only a single divisor digit, we can use a fast path (cf.
8517
- * Knuth section 4.3.1 exercise 16).
8518
- */
8519
- divisor1 = divisor [1 ];
8520
- carry = 0 ;
8521
- for (i = 0 ; i < res_ndigits ; i ++ )
8522
- {
8523
- carry = carry * NBASE + dividend [i + 1 ];
8524
- res_digits [i ] = carry / divisor1 ;
8525
- carry = carry % divisor1 ;
8526
- }
8527
- }
8528
- else
8529
- {
8530
8540
/*
8531
8541
* The full multiple-place algorithm is taken from Knuth volume 2,
8532
8542
* Algorithm 4.3.1D.
@@ -8659,7 +8669,6 @@ div_var(const NumericVar *var1, const NumericVar *var2, NumericVar *result,
8659
8669
/* And we're done with this quotient digit */
8660
8670
res_digits [j ] = qhat ;
8661
8671
}
8662
- }
8663
8672
8664
8673
pfree (dividend );
8665
8674
@@ -8735,8 +8744,33 @@ div_var_fast(const NumericVar *var1, const NumericVar *var2,
8735
8744
errmsg ("division by zero" )));
8736
8745
8737
8746
/*
8738
- * Now result zero check
8747
+ * If the divisor has just one or two digits, delegate to div_var_int(),
8748
+ * which uses fast short division.
8739
8749
*/
8750
+ if (var2ndigits <= 2 )
8751
+ {
8752
+ int idivisor ;
8753
+ int idivisor_weight ;
8754
+
8755
+ idivisor = var2 -> digits [0 ];
8756
+ idivisor_weight = var2 -> weight ;
8757
+ if (var2ndigits == 2 )
8758
+ {
8759
+ idivisor = idivisor * NBASE + var2 -> digits [1 ];
8760
+ idivisor_weight -- ;
8761
+ }
8762
+ if (var2 -> sign == NUMERIC_NEG )
8763
+ idivisor = - idivisor ;
8764
+
8765
+ div_var_int (var1 , idivisor , idivisor_weight , result , rscale , round );
8766
+ return ;
8767
+ }
8768
+
8769
+ /*
8770
+ * Otherwise, perform full long division.
8771
+ */
8772
+
8773
+ /* Result zero check */
8740
8774
if (var1ndigits == 0 )
8741
8775
{
8742
8776
zero_var (result );
@@ -9008,6 +9042,118 @@ div_var_fast(const NumericVar *var1, const NumericVar *var2,
9008
9042
}
9009
9043
9010
9044
9045
+ /*
9046
+ * div_var_int() -
9047
+ *
9048
+ * Divide a numeric variable by a 32-bit integer with the specified weight.
9049
+ * The quotient var / (ival * NBASE^ival_weight) is stored in result.
9050
+ */
9051
+ static void
9052
+ div_var_int (const NumericVar * var , int ival , int ival_weight ,
9053
+ NumericVar * result , int rscale , bool round )
9054
+ {
9055
+ NumericDigit * var_digits = var -> digits ;
9056
+ int var_ndigits = var -> ndigits ;
9057
+ int res_sign ;
9058
+ int res_weight ;
9059
+ int res_ndigits ;
9060
+ NumericDigit * res_buf ;
9061
+ NumericDigit * res_digits ;
9062
+ uint32 divisor ;
9063
+ int i ;
9064
+
9065
+ /* Guard against division by zero */
9066
+ if (ival == 0 )
9067
+ ereport (ERROR ,
9068
+ errcode (ERRCODE_DIVISION_BY_ZERO ),
9069
+ errmsg ("division by zero" ));
9070
+
9071
+ /* Result zero check */
9072
+ if (var_ndigits == 0 )
9073
+ {
9074
+ zero_var (result );
9075
+ result -> dscale = rscale ;
9076
+ return ;
9077
+ }
9078
+
9079
+ /*
9080
+ * Determine the result sign, weight and number of digits to calculate.
9081
+ * The weight figured here is correct if the emitted quotient has no
9082
+ * leading zero digits; otherwise strip_var() will fix things up.
9083
+ */
9084
+ if (var -> sign == NUMERIC_POS )
9085
+ res_sign = ival > 0 ? NUMERIC_POS : NUMERIC_NEG ;
9086
+ else
9087
+ res_sign = ival > 0 ? NUMERIC_NEG : NUMERIC_POS ;
9088
+ res_weight = var -> weight - ival_weight ;
9089
+ /* The number of accurate result digits we need to produce: */
9090
+ res_ndigits = res_weight + 1 + (rscale + DEC_DIGITS - 1 ) / DEC_DIGITS ;
9091
+ /* ... but always at least 1 */
9092
+ res_ndigits = Max (res_ndigits , 1 );
9093
+ /* If rounding needed, figure one more digit to ensure correct result */
9094
+ if (round )
9095
+ res_ndigits ++ ;
9096
+
9097
+ res_buf = digitbuf_alloc (res_ndigits + 1 );
9098
+ res_buf [0 ] = 0 ; /* spare digit for later rounding */
9099
+ res_digits = res_buf + 1 ;
9100
+
9101
+ /*
9102
+ * Now compute the quotient digits. This is the short division algorithm
9103
+ * described in Knuth volume 2, section 4.3.1 exercise 16, except that we
9104
+ * allow the divisor to exceed the internal base.
9105
+ *
9106
+ * In this algorithm, the carry from one digit to the next is at most
9107
+ * divisor - 1. Therefore, while processing the next digit, carry may
9108
+ * become as large as divisor * NBASE - 1, and so it requires a 64-bit
9109
+ * integer if this exceeds UINT_MAX.
9110
+ */
9111
+ divisor = Abs (ival );
9112
+
9113
+ if (divisor <= UINT_MAX / NBASE )
9114
+ {
9115
+ /* carry cannot overflow 32 bits */
9116
+ uint32 carry = 0 ;
9117
+
9118
+ for (i = 0 ; i < res_ndigits ; i ++ )
9119
+ {
9120
+ carry = carry * NBASE + (i < var_ndigits ? var_digits [i ] : 0 );
9121
+ res_digits [i ] = (NumericDigit ) (carry / divisor );
9122
+ carry = carry % divisor ;
9123
+ }
9124
+ }
9125
+ else
9126
+ {
9127
+ /* carry may exceed 32 bits */
9128
+ uint64 carry = 0 ;
9129
+
9130
+ for (i = 0 ; i < res_ndigits ; i ++ )
9131
+ {
9132
+ carry = carry * NBASE + (i < var_ndigits ? var_digits [i ] : 0 );
9133
+ res_digits [i ] = (NumericDigit ) (carry / divisor );
9134
+ carry = carry % divisor ;
9135
+ }
9136
+ }
9137
+
9138
+ /* Store the quotient in result */
9139
+ digitbuf_free (result -> buf );
9140
+ result -> ndigits = res_ndigits ;
9141
+ result -> buf = res_buf ;
9142
+ result -> digits = res_digits ;
9143
+ result -> weight = res_weight ;
9144
+ result -> sign = res_sign ;
9145
+
9146
+ /* Round or truncate to target rscale (and set result->dscale) */
9147
+ if (round )
9148
+ round_var (result , rscale );
9149
+ else
9150
+ trunc_var (result , rscale );
9151
+
9152
+ /* Strip leading/trailing zeroes */
9153
+ strip_var (result );
9154
+ }
9155
+
9156
+
9011
9157
/*
9012
9158
* Default scale selection for division
9013
9159
*
@@ -9783,7 +9929,7 @@ exp_var(const NumericVar *arg, NumericVar *result, int rscale)
9783
9929
{
9784
9930
NumericVar x ;
9785
9931
NumericVar elem ;
9786
- NumericVar ni ;
9932
+ int ni ;
9787
9933
double val ;
9788
9934
int dweight ;
9789
9935
int ndiv2 ;
@@ -9792,7 +9938,6 @@ exp_var(const NumericVar *arg, NumericVar *result, int rscale)
9792
9938
9793
9939
init_var (& x );
9794
9940
init_var (& elem );
9795
- init_var (& ni );
9796
9941
9797
9942
set_var_from_var (arg , & x );
9798
9943
@@ -9820,29 +9965,24 @@ exp_var(const NumericVar *arg, NumericVar *result, int rscale)
9820
9965
9821
9966
/*
9822
9967
* Reduce x to the range -0.01 <= x <= 0.01 (approximately) by dividing by
9823
- * 2^n, to improve the convergence rate of the Taylor series.
9968
+ * 2^ndiv2, to improve the convergence rate of the Taylor series.
9969
+ *
9970
+ * Note that the overflow check above ensures that Abs(x) < 6000, which
9971
+ * means that ndiv2 <= 20 here.
9824
9972
*/
9825
9973
if (Abs (val ) > 0.01 )
9826
9974
{
9827
- NumericVar tmp ;
9828
-
9829
- init_var (& tmp );
9830
- set_var_from_var (& const_two , & tmp );
9831
-
9832
9975
ndiv2 = 1 ;
9833
9976
val /= 2 ;
9834
9977
9835
9978
while (Abs (val ) > 0.01 )
9836
9979
{
9837
9980
ndiv2 ++ ;
9838
9981
val /= 2 ;
9839
- add_var (& tmp , & tmp , & tmp );
9840
9982
}
9841
9983
9842
9984
local_rscale = x .dscale + ndiv2 ;
9843
- div_var_fast (& x , & tmp , & x , local_rscale , true);
9844
-
9845
- free_var (& tmp );
9985
+ div_var_int (& x , 1 << ndiv2 , 0 , & x , local_rscale , true);
9846
9986
}
9847
9987
else
9848
9988
ndiv2 = 0 ;
@@ -9870,16 +10010,16 @@ exp_var(const NumericVar *arg, NumericVar *result, int rscale)
9870
10010
add_var (& const_one , & x , result );
9871
10011
9872
10012
mul_var (& x , & x , & elem , local_rscale );
9873
- set_var_from_var ( & const_two , & ni ) ;
9874
- div_var_fast (& elem , & ni , & elem , local_rscale , true);
10013
+ ni = 2 ;
10014
+ div_var_int (& elem , ni , 0 , & elem , local_rscale , true);
9875
10015
9876
10016
while (elem .ndigits != 0 )
9877
10017
{
9878
10018
add_var (result , & elem , result );
9879
10019
9880
10020
mul_var (& elem , & x , & elem , local_rscale );
9881
- add_var ( & ni , & const_one , & ni ) ;
9882
- div_var_fast (& elem , & ni , & elem , local_rscale , true);
10021
+ ni ++ ;
10022
+ div_var_int (& elem , ni , 0 , & elem , local_rscale , true);
9883
10023
}
9884
10024
9885
10025
/*
@@ -9899,7 +10039,6 @@ exp_var(const NumericVar *arg, NumericVar *result, int rscale)
9899
10039
9900
10040
free_var (& x );
9901
10041
free_var (& elem );
9902
- free_var (& ni );
9903
10042
}
9904
10043
9905
10044
@@ -9993,7 +10132,7 @@ ln_var(const NumericVar *arg, NumericVar *result, int rscale)
9993
10132
{
9994
10133
NumericVar x ;
9995
10134
NumericVar xx ;
9996
- NumericVar ni ;
10135
+ int ni ;
9997
10136
NumericVar elem ;
9998
10137
NumericVar fact ;
9999
10138
int nsqrt ;
@@ -10012,7 +10151,6 @@ ln_var(const NumericVar *arg, NumericVar *result, int rscale)
10012
10151
10013
10152
init_var (& x );
10014
10153
init_var (& xx );
10015
- init_var (& ni );
10016
10154
init_var (& elem );
10017
10155
init_var (& fact );
10018
10156
@@ -10073,13 +10211,13 @@ ln_var(const NumericVar *arg, NumericVar *result, int rscale)
10073
10211
set_var_from_var (result , & xx );
10074
10212
mul_var (result , result , & x , local_rscale );
10075
10213
10076
- set_var_from_var ( & const_one , & ni ) ;
10214
+ ni = 1 ;
10077
10215
10078
10216
for (;;)
10079
10217
{
10080
- add_var ( & ni , & const_two , & ni ) ;
10218
+ ni += 2 ;
10081
10219
mul_var (& xx , & x , & xx , local_rscale );
10082
- div_var_fast (& xx , & ni , & elem , local_rscale , true);
10220
+ div_var_int (& xx , ni , 0 , & elem , local_rscale , true);
10083
10221
10084
10222
if (elem .ndigits == 0 )
10085
10223
break ;
@@ -10095,7 +10233,6 @@ ln_var(const NumericVar *arg, NumericVar *result, int rscale)
10095
10233
10096
10234
free_var (& x );
10097
10235
free_var (& xx );
10098
- free_var (& ni );
10099
10236
free_var (& elem );
10100
10237
free_var (& fact );
10101
10238
}
0 commit comments