@@ -319,110 +319,192 @@ BigDecimal_prec(VALUE self)
319
319
return obj ;
320
320
}
321
321
322
- /*
323
- * call-seq:
324
- * precision -> integer
325
- *
326
- * Returns the number of decimal digits in +self+:
327
- *
328
- * BigDecimal("0").precision # => 0
329
- * BigDecimal("1").precision # => 1
330
- * BigDecimal("-1e20").precision # => 21
331
- * BigDecimal("1e-20").precision # => 20
332
- * BigDecimal("Infinity").precision # => 0
333
- * BigDecimal("-Infinity").precision # => 0
334
- * BigDecimal("NaN").precision # => 0
335
- *
336
- */
337
- static VALUE
338
- BigDecimal_precision (VALUE self )
322
+ static void
323
+ BigDecimal_count_precision_and_scale (VALUE self , ssize_t * out_precision , ssize_t * out_scale )
339
324
{
340
325
ENTER (1 );
341
326
327
+ if (out_precision == NULL && out_scale == NULL )
328
+ return ;
329
+
342
330
Real * p ;
343
331
GUARD_OBJ (p , GetVpValue (self , 1 ));
344
- if (VpIsZero (p ) || !VpIsDef (p )) return INT2FIX (0 );
332
+ if (VpIsZero (p ) || !VpIsDef (p )) {
333
+ zero :
334
+ if (out_precision ) * out_precision = 0 ;
335
+ if (out_scale ) * out_scale = 0 ;
336
+ return ;
337
+ }
338
+
339
+ DECDIG x ;
340
+
341
+ ssize_t n = p -> Prec ; /* The length of frac without zeros. */
342
+ while (n > 0 && p -> frac [n - 1 ] == 0 ) -- n ;
343
+ if (n == 0 ) goto zero ;
344
+
345
+ int nlz = BASE_FIG ;
346
+ for (x = p -> frac [0 ]; x > 0 ; x /= 10 ) -- nlz ;
347
+
348
+ int ntz = 0 ;
349
+ for (x = p -> frac [n - 1 ]; x > 0 && x % 10 == 0 ; x /= 10 ) ++ ntz ;
345
350
346
351
/*
347
- * The most significant digit is frac[0], and the least significant digit is frac[Prec-1].
348
- * When the exponent is zero, the decimal point is located just before frac[0].
352
+ * Calculate the precision and the scale
353
+ * -------------------------------------
349
354
*
355
+ * The most significant digit is frac[0], and the least significant digit
356
+ * is frac[Prec-1]. When the exponent is zero, the decimal point is
357
+ * located just before frac[0].
350
358
*
351
359
* When the exponent is negative, the decimal point moves to leftward.
352
- * In this case, the precision can be calculated by BASE_FIG * (-exponent + Prec) - ntz.
360
+ * In this case, the precision can be calculated by
361
+ *
362
+ * precision = BASE_FIG * (-exponent + n) - ntz,
363
+ *
364
+ * and the scale is the same as precision.
353
365
*
354
- * 0 . 0000 0000 | frac[0] frac[1] ... frac[Prec-1]
355
- * <----------| exponent == -2
366
+ * 0 . 0000 0000 | frac[0] ... frac[n-1] |
367
+ * |<----------| exponent == -2 |
368
+ * |---------------------------------->| precision
369
+ * |---------------------------------->| scale
356
370
*
357
- * Conversely, when the exponent is positive, the decimal point moves to rightward.
358
371
*
359
- * | frac[0] frac[1] frac[2] . frac[3] frac[4] ... frac[Prec-1]
360
- * |------------------------> exponent == 3
372
+ * Conversely, when the exponent is positive, the decimal point moves to
373
+ * rightward. In this case, the scale equals to
374
+ *
375
+ * BASE_FIG * (n - exponent) - ntz.
376
+ *
377
+ * the precision equals to
378
+ *
379
+ * scale + BASE_FIG * exponent - nlz.
380
+ *
381
+ * | frac[0] frac[1] . frac[2] ... frac[n-1] |
382
+ * |---------------->| exponent == 2 |
383
+ * | |---------------------->| scale
384
+ * |---------------------------------------->| precision
361
385
*/
362
386
363
387
ssize_t ex = p -> exponent ;
364
388
365
389
/* Count the number of decimal digits before frac[1]. */
366
- ssize_t precision = BASE_FIG ; /* The number of decimal digits in frac[0]. */
390
+ ssize_t n_digits_head = BASE_FIG ;
367
391
if (ex < 0 ) {
368
- precision += - ex * BASE_FIG ; /* The number of leading zeros before frac[0]. */
369
- ex = 0 ;
392
+ n_digits_head += ( - ex ) * BASE_FIG ; /* The number of leading zeros before frac[0]. */
393
+ ex = 0 ;
370
394
}
371
395
else if (ex > 0 ) {
372
- /* Count the number of decimal digits without the leading zeros in
373
- * the most significant digit in the integral part. */
374
- DECDIG x = p -> frac [0 ];
375
- for (precision = 0 ; x > 0 ; x /= 10 ) {
376
- ++ precision ;
377
- }
396
+ /* Count the number of decimal digits without the leading zeros in
397
+ * the most significant digit in the integral part.
398
+ */
399
+ n_digits_head -= nlz ; /* Make the number of digits */
378
400
}
379
401
380
- /* Count the number of decimal digits after frac[0]. */
381
- if (ex > (ssize_t )p -> Prec ) {
382
- /* In this case the number is an integer with multiple trailing zeros. */
383
- precision += (ex - 1 ) * BASE_FIG ;
402
+ if (out_precision ) {
403
+ ssize_t precision = n_digits_head ;
404
+
405
+ /* Count the number of decimal digits after frac[0]. */
406
+ if (ex > (ssize_t )n ) {
407
+ /* In this case the number is an integer with some trailing zeros. */
408
+ precision += (ex - 1 ) * BASE_FIG ;
409
+ }
410
+ else if (n > 0 ) {
411
+ precision += (n - 1 ) * BASE_FIG ;
412
+
413
+ if (ex < (ssize_t )n ) {
414
+ precision -= ntz ;
415
+ }
416
+ }
417
+
418
+ * out_precision = precision ;
384
419
}
385
- else if (p -> Prec > 0 ) {
386
- ssize_t n = (ssize_t )p -> Prec - 1 ;
387
- while (n > 0 && p -> frac [n ] == 0 ) -- n ; /* Skip trailing zeros, just in case. */
388
420
389
- precision += n * BASE_FIG ;
421
+ if (out_scale ) {
422
+ ssize_t scale = 0 ;
390
423
391
- if (ex < ( ssize_t ) p -> Prec ) {
392
- DECDIG x = p -> frac [ n ] ;
393
- for (; x > 0 && x % 10 == 0 ; x /= 10 ) {
394
- -- precision ;
395
- }
424
+ if (p -> exponent < 0 ) {
425
+ scale = n_digits_head + ( n - 1 ) * BASE_FIG - ntz ;
426
+ }
427
+ else if ( n > p -> exponent ) {
428
+ scale = ( n - p -> exponent ) * BASE_FIG - ntz ;
396
429
}
430
+
431
+ * out_scale = scale ;
397
432
}
433
+ }
398
434
435
+ /*
436
+ * call-seq:
437
+ * precision -> integer
438
+ *
439
+ * Returns the number of decimal digits in +self+:
440
+ *
441
+ * BigDecimal("0").precision # => 0
442
+ * BigDecimal("1").precision # => 1
443
+ * BigDecimal("1.1").precision # => 2
444
+ * BigDecimal("3.1415").precision # => 5
445
+ * BigDecimal("-1e20").precision # => 21
446
+ * BigDecimal("1e-20").precision # => 20
447
+ * BigDecimal("Infinity").precision # => 0
448
+ * BigDecimal("-Infinity").precision # => 0
449
+ * BigDecimal("NaN").precision # => 0
450
+ *
451
+ */
452
+ static VALUE
453
+ BigDecimal_precision (VALUE self )
454
+ {
455
+ ssize_t precision ;
456
+ BigDecimal_count_precision_and_scale (self , & precision , NULL );
399
457
return SSIZET2NUM (precision );
400
458
}
401
459
460
+ /*
461
+ * call-seq:
462
+ * scale -> integer
463
+ *
464
+ * Returns the number of decimal digits following the decimal digits in +self+.
465
+ *
466
+ * BigDecimal("0").scale # => 0
467
+ * BigDecimal("1").scale # => 1
468
+ * BigDecimal("1.1").scale # => 1
469
+ * BigDecimal("3.1415").scale # => 4
470
+ * BigDecimal("-1e20").precision # => 0
471
+ * BigDecimal("1e-20").precision # => 20
472
+ * BigDecimal("Infinity").scale # => 0
473
+ * BigDecimal("-Infinity").scale # => 0
474
+ * BigDecimal("NaN").scale # => 0
475
+ */
476
+ static VALUE
477
+ BigDecimal_scale (VALUE self )
478
+ {
479
+ ssize_t scale ;
480
+ BigDecimal_count_precision_and_scale (self , NULL , & scale );
481
+ return SSIZET2NUM (scale );
482
+ }
483
+
402
484
static VALUE
403
485
BigDecimal_n_significant_digits (VALUE self )
404
486
{
405
487
ENTER (1 );
406
488
407
489
Real * p ;
408
490
GUARD_OBJ (p , GetVpValue (self , 1 ));
409
-
410
- ssize_t n = p -> Prec ;
411
- while (n > 0 && p -> frac [n - 1 ] == 0 ) -- n ;
412
- if (n <= 0 ) {
491
+ if (VpIsZero (p ) || !VpIsDef (p )) {
413
492
return INT2FIX (0 );
414
493
}
415
494
416
- int nlz , ntz ;
495
+ ssize_t n = p -> Prec ; /* The length of frac without trailing zeros. */
496
+ for (n = p -> Prec ; n > 0 && p -> frac [n - 1 ] == 0 ; -- n );
497
+ if (n == 0 ) return INT2FIX (0 );
417
498
418
- DECDIG x = p -> frac [0 ];
419
- for (nlz = BASE_FIG ; x > 0 ; x /= 10 ) -- nlz ;
499
+ DECDIG x ;
500
+ int nlz = BASE_FIG ;
501
+ for (x = p -> frac [0 ]; x > 0 ; x /= 10 ) -- nlz ;
420
502
421
- x = p -> frac [ n - 1 ] ;
422
- for (ntz = 0 ; x > 0 && x % 10 == 0 ; x /= 10 ) ++ ntz ;
503
+ int ntz = 0 ;
504
+ for (x = p -> frac [ n - 1 ] ; x > 0 && x % 10 == 0 ; x /= 10 ) ++ ntz ;
423
505
424
- ssize_t n_digits = BASE_FIG * n - nlz - ntz ;
425
- return SSIZET2NUM (n_digits );
506
+ ssize_t n_significant_digits = BASE_FIG * n - nlz - ntz ;
507
+ return SSIZET2NUM (n_significant_digits );
426
508
}
427
509
428
510
/*
@@ -4129,6 +4211,7 @@ Init_bigdecimal(void)
4129
4211
/* instance methods */
4130
4212
rb_define_method (rb_cBigDecimal , "precs" , BigDecimal_prec , 0 );
4131
4213
rb_define_method (rb_cBigDecimal , "precision" , BigDecimal_precision , 0 );
4214
+ rb_define_method (rb_cBigDecimal , "scale" , BigDecimal_scale , 0 );
4132
4215
rb_define_method (rb_cBigDecimal , "n_significant_digits" , BigDecimal_n_significant_digits , 0 );
4133
4216
4134
4217
rb_define_method (rb_cBigDecimal , "add" , BigDecimal_add2 , 2 );
0 commit comments