001/** 002 * RoundingStrategy.java 003 * 004 * Copyright (c) 2004-2012, Nicole C. Tedesco. All rights reserved. 005 * 006 * Licensed under the Apache License, Version 2.0 (the "License"); 007 * you may not use this file except in compliance with the License. 008 * You may obtain a copy of the License at: 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, software 013 * distributed under the License is distributed on an "AS IS" BASIS, 014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 015 * See the License for the specific language governing permissions and 016 * limitations under the License. 017 */ 018 019package net.sf.jaccumulator.scalars; 020 021import java.math.*; 022import java.util.EnumMap; 023import java.util.Map; 024 025// TABLE OF CONTENTS 026// ================= 027// Select the entire text line of the subject you want to jump to (including the 028// leading slashes), then execute a Find on that topic (usually Ctrl+F). In 029// most editors, the Find function will automatically replace the "find" topic 030// with your highlighted text. If not then you may need to copy then paste your 031// topic into the appropriate field. 032// 033// * Initialization and Finalization 034// * Rounding Modes 035// * Factories 036// * Conversions 037// 038// * Ceiling 039// * Down 040// * Floor 041// * Half Down 042// * Half Even 043// * Half Up 044// * Up 045// * Unnecessary 046// 047 048/** 049 * Strategies for floating point-to-integral conversions 050 * 051 * @since JAccumulator 4.0 052 * @author Nicole Tedesco (<a 053 * href="mailto:Nicole@NicoleTedesco.com">Nicole@NicoleTedesco.com</a>) 054 */ 055public abstract class RoundingStrategy 056{ 057 private final static Map<RoundingMode,RoundingStrategy> _theStrategies = new EnumMap<RoundingMode,RoundingStrategy>( 058 RoundingMode.class); 059 060 protected static final int CACHE_SIZE = 10; 061 062 /** 063 * @see Math#ceil(double) 064 * @see RoundingMode#CEILING 065 */ 066 public final static RoundingStrategy CEILING = new Ceiling(); 067 068 /** 069 * @see RoundingMode#DOWN 070 */ 071 public final static RoundingStrategy DOWN = new Down(); 072 073 /** 074 * @see Math#floor(double) 075 * @see RoundingMode#FLOOR 076 */ 077 public final static RoundingStrategy FLOOR = new Floor(); 078 079 /** 080 * @see RoundingMode#HALF_DOWN 081 */ 082 public final static RoundingStrategy HALF_DOWN = new HalfDown(); 083 084 /** 085 * @see Math#rint(double) 086 * @see RoundingMode#HALF_EVEN 087 */ 088 public final static RoundingStrategy HALF_EVEN = new HalfEven(); 089 090 /** 091 * @see RoundingMode#HALF_UP 092 */ 093 public final static RoundingStrategy HALF_UP = new HalfUp(); 094 095 /** 096 * @see RoundingMode#UNNECESSARY 097 */ 098 public final static RoundingStrategy UNNECESSARY = new Unnecessary(); 099 100 /** 101 * @see RoundingMode#UP 102 */ 103 public final static RoundingStrategy UP = new Up(); 104 105 static { 106 _theStrategies.put(CEILING.getRoundingMode(), CEILING); 107 _theStrategies.put(DOWN.getRoundingMode(), DOWN); 108 _theStrategies.put(FLOOR.getRoundingMode(), FLOOR); 109 _theStrategies.put(HALF_DOWN.getRoundingMode(), HALF_DOWN); 110 _theStrategies.put(HALF_EVEN.getRoundingMode(), HALF_EVEN); 111 _theStrategies.put(HALF_UP.getRoundingMode(), HALF_UP); 112 _theStrategies.put(UP.getRoundingMode(), UP); 113 _theStrategies.put(UNNECESSARY.getRoundingMode(), UNNECESSARY); 114 } 115 protected final MathContext[] _theContextCache; 116 117 // ---------- 118 // * Initialization and Finalization 119 // 120 121 protected RoundingStrategy() 122 { 123 final RoundingMode aMode = this.getRoundingMode(); 124 this._theContextCache = new MathContext[CACHE_SIZE]; 125 for (int i = 0; i < CACHE_SIZE; i++) { 126 this._theContextCache[i] = new MathContext(i, aMode); 127 } 128 } 129 130 // ---------- 131 // * Rounding Modes 132 // 133 134 public abstract int getBigDecimalRoundingMode(); 135 136 public MathContext getMathContext( final int precision ) { 137 if ((0 <= precision) && (precision < CACHE_SIZE)) { 138 return this._theContextCache[precision]; 139 } 140 return new MathContext(precision, this.getRoundingMode()); 141 } 142 143 // ---------- 144 // * Conversions 145 // 146 147 public abstract RoundingMode getRoundingMode(); 148 149 public final boolean booleanValue( final double aNumber ) { 150 return this.longValue(aNumber) != 0L; 151 } 152 153 public final boolean booleanValue( final float aNumber ) { 154 return this.longValue(aNumber) != 0L; 155 } 156 157 public final byte byteValue( final double aNumber ) { 158 return (byte)this.intValue(aNumber); 159 } 160 161 public final byte byteValue( final float aNumber ) { 162 return (byte)this.intValue(aNumber); 163 } 164 165 public final char charValue( final double aNumber ) { 166 return (char)this.intValue(aNumber); 167 } 168 169 public final char charValue( final float aNumber ) { 170 return (char)this.intValue(aNumber); 171 } 172 173 public abstract double doubleValue( final double aNumber ); 174 175 public final float floatValue( final float aNumber ) { 176 return (float)this.doubleValue(aNumber); 177 } 178 179 public abstract int intValue( final double aNumber ); 180 181 public abstract int intValue( final float aNumber ); 182 183 public abstract long longValue( final double aNumber ); 184 185 public abstract long longValue( final float aNumber ); 186 187 public final short shortValue( final double aNumber ) { 188 return (short)this.intValue(aNumber); 189 } 190 191 public final short shortValue( final float aNumber ) { 192 return (short)this.intValue(aNumber); 193 } 194 195 public final BigDecimal toUnlimitedDecimal( final BigDecimal aNumber ) { 196 final RoundingMode aRoundingMode = this.getRoundingMode(); 197 final BigDecimal bdNew = aNumber.setScale(0, aRoundingMode); 198 return bdNew; 199 } 200 201 public final BigInteger toUnlimitedInteger( final double aNumber ) { 202 final BigDecimal bd = toUnlimitedDecimal(aNumber); 203 final BigDecimal rounded = this.toUnlimitedDecimal(bd); 204 final BigInteger bi = rounded.toBigInteger(); 205 return bi; 206 } 207 208 // ---------- 209 // * Factories 210 // 211 212 public final BigInteger toUnlimitedInteger( final float aNumber ) { 213 final BigDecimal bd = toUnlimitedDecimal(aNumber); 214 final BigDecimal rounded = this.toUnlimitedDecimal(bd); 215 final BigInteger bi = rounded.toBigInteger(); 216 return bi; 217 } 218 219 public final static RoundingStrategy getInstance( 220 final int aBigDecimalRoundingMode ) 221 { 222 return getInstance(RoundingMode.valueOf(aBigDecimalRoundingMode)); 223 } 224 225 public final static RoundingStrategy getInstance( final RoundingMode aMode ) 226 { 227 return _theStrategies.get(aMode); 228 } 229 230 // ---------- 231 // * Ceiling 232 // 233 234 private static class Ceiling 235 extends 236 RoundingStrategy 237 { 238 public Ceiling() 239 { 240 } 241 242 @Override 243 public final int getBigDecimalRoundingMode() { 244 return BigDecimal.ROUND_CEILING; 245 } 246 247 @Override 248 public final RoundingMode getRoundingMode() { 249 return RoundingMode.CEILING; 250 } 251 252 @Override 253 public final double doubleValue( final double aNumber ) { 254 return Math.ceil(aNumber); 255 } 256 257 @Override 258 public final int intValue( final double aNumber ) { 259 return (int)this.doubleValue(aNumber); 260 } 261 262 @Override 263 public final int intValue( final float aNumber ) { 264 return (int)this.doubleValue(aNumber); 265 } 266 267 @Override 268 public final long longValue( final double aNumber ) { 269 return (long)this.doubleValue(aNumber); 270 } 271 272 @Override 273 public final long longValue( final float aNumber ) { 274 return (long)this.doubleValue(aNumber); 275 } 276 } 277 278 // ---------- 279 // * Down 280 // 281 282 private static class Down 283 extends 284 RoundingStrategy 285 { 286 public Down() 287 { 288 } 289 290 @Override 291 public final int getBigDecimalRoundingMode() { 292 return BigDecimal.ROUND_DOWN; 293 } 294 295 @Override 296 public final RoundingMode getRoundingMode() { 297 return RoundingMode.DOWN; 298 } 299 300 @Override 301 public final double doubleValue( final double aNumber ) { 302 return (long)aNumber; 303 } 304 305 @Override 306 public final int intValue( final double aNumber ) { 307 return (int)aNumber; 308 } 309 310 @Override 311 public final int intValue( final float aNumber ) { 312 return (int)aNumber; 313 } 314 315 @Override 316 public final long longValue( final double aNumber ) { 317 return (long)aNumber; 318 } 319 320 @Override 321 public final long longValue( final float aNumber ) { 322 return (long)aNumber; 323 } 324 } 325 326 // ---------- 327 // * Floor 328 // 329 330 private static class Floor 331 extends 332 RoundingStrategy 333 { 334 public Floor() 335 { 336 } 337 338 @Override 339 public final int getBigDecimalRoundingMode() { 340 return BigDecimal.ROUND_FLOOR; 341 } 342 343 @Override 344 public final RoundingMode getRoundingMode() { 345 return RoundingMode.FLOOR; 346 } 347 348 @Override 349 public final double doubleValue( final double aNumber ) { 350 return Math.floor(aNumber); 351 } 352 353 @Override 354 public final int intValue( final double aNumber ) { 355 return (int)this.doubleValue(aNumber); 356 } 357 358 @Override 359 public final int intValue( final float aNumber ) { 360 return (int)this.doubleValue(aNumber); 361 } 362 363 @Override 364 public final long longValue( final double aNumber ) { 365 return (long)this.doubleValue(aNumber); 366 } 367 368 @Override 369 public final long longValue( final float aNumber ) { 370 return (long)this.doubleValue(aNumber); 371 } 372 } 373 374 // ---------- 375 // * Half Down 376 // 377 378 private static class HalfDown 379 extends 380 RoundingStrategy 381 { 382 public HalfDown() 383 { 384 } 385 386 @Override 387 public final int getBigDecimalRoundingMode() { 388 return BigDecimal.ROUND_HALF_DOWN; 389 } 390 391 @Override 392 public final RoundingMode getRoundingMode() { 393 return RoundingMode.HALF_DOWN; 394 } 395 396 @Override 397 public final double doubleValue( final double aNumber ) { 398 if (aNumber < 0.0D) { 399 if (DOWN.doubleValue(aNumber) == (aNumber + 0.5D)) { 400 return DOWN.doubleValue(aNumber); 401 } 402 return (long)(aNumber - 0.5D); 403 } 404 if (DOWN.doubleValue(aNumber) == (aNumber - 0.5D)) { 405 return DOWN.doubleValue(aNumber); 406 } 407 return (long)(aNumber + 0.5D); 408 } 409 410 @Override 411 public final int intValue( final double aNumber ) { 412 return (int)this.longValue(aNumber); 413 } 414 415 @Override 416 public final int intValue( final float aNumber ) { 417 return (int)this.longValue(aNumber); 418 } 419 420 @Override 421 public final long longValue( final double aNumber ) { 422 if (aNumber < 0.0D) { 423 if (DOWN.doubleValue(aNumber) == (aNumber + 0.5D)) { 424 return DOWN.longValue(aNumber); 425 } 426 return (long)(aNumber - 0.5D); 427 } 428 if (DOWN.doubleValue(aNumber) == (aNumber - 0.5D)) { 429 return DOWN.longValue(aNumber); 430 } 431 return (long)(aNumber + 0.5D); 432 } 433 434 @Override 435 public final long longValue( final float aNumber ) { 436 if (aNumber < 0.0D) { 437 if (DOWN.doubleValue(aNumber) == (aNumber + 0.5D)) { 438 return DOWN.longValue(aNumber); 439 } 440 return (long)(aNumber - 0.5D); 441 } 442 if (DOWN.doubleValue(aNumber) == (aNumber - 0.5D)) { 443 return DOWN.longValue(aNumber); 444 } 445 return (long)(aNumber + 0.5D); 446 } 447 } 448 449 // ---------- 450 // * Half Even 451 // 452 453 private static class HalfEven 454 extends 455 RoundingStrategy 456 { 457 public HalfEven() 458 { 459 } 460 461 @Override 462 public final int getBigDecimalRoundingMode() { 463 return BigDecimal.ROUND_HALF_EVEN; 464 } 465 466 @Override 467 public final RoundingMode getRoundingMode() { 468 return RoundingMode.HALF_EVEN; 469 } 470 471 @Override 472 public final double doubleValue( final double aNumber ) { 473 return Math.rint(aNumber); 474 } 475 476 @Override 477 public final int intValue( final double aNumber ) { 478 return (int)this.doubleValue(aNumber); 479 } 480 481 @Override 482 public final int intValue( final float aNumber ) { 483 return (int)this.doubleValue(aNumber); 484 } 485 486 @Override 487 public final long longValue( final double aNumber ) { 488 return (long)this.doubleValue(aNumber); 489 } 490 491 @Override 492 public final long longValue( final float aNumber ) { 493 return (long)this.doubleValue(aNumber); 494 } 495 } 496 497 // ---------- 498 // * Half Up 499 // 500 501 private static class HalfUp 502 extends 503 RoundingStrategy 504 { 505 public HalfUp() 506 { 507 } 508 509 @Override 510 public final int getBigDecimalRoundingMode() { 511 return BigDecimal.ROUND_HALF_UP; 512 } 513 514 @Override 515 public final RoundingMode getRoundingMode() { 516 return RoundingMode.HALF_UP; 517 } 518 519 @Override 520 public final double doubleValue( final double aNumber ) { 521 return this.longValue(aNumber); 522 } 523 524 @Override 525 public final int intValue( final double aNumber ) { 526 if (aNumber < 0.0D) { 527 return (int)(aNumber - 0.5D); 528 } 529 return (int)(aNumber + 0.5D); 530 } 531 532 @Override 533 public final int intValue( final float aNumber ) { 534 if (aNumber < 0.0F) { 535 return (int)(aNumber - 0.5F); 536 } 537 return (int)(aNumber + 0.5F); 538 } 539 540 @Override 541 public final long longValue( final double aNumber ) { 542 if (aNumber < 0.0D) { 543 return (long)(aNumber - 0.5D); 544 } 545 return (long)(aNumber + 0.5D); 546 } 547 548 @Override 549 public final long longValue( final float aNumber ) { 550 if (aNumber < 0.0F) { 551 return (long)(aNumber - 0.5F); 552 } 553 return (long)(aNumber + 0.5F); 554 } 555 } 556 557 // ---------- 558 // * Up 559 // 560 561 private static class Unnecessary 562 extends 563 RoundingStrategy 564 { 565 public Unnecessary() 566 { 567 } 568 569 @Override 570 public final int getBigDecimalRoundingMode() { 571 return BigDecimal.ROUND_UNNECESSARY; 572 } 573 574 @Override 575 public final RoundingMode getRoundingMode() { 576 return RoundingMode.UNNECESSARY; 577 } 578 579 @Override 580 public final double doubleValue( final double aNumber ) { 581 if (DOWN.doubleValue(aNumber) == aNumber) { 582 return aNumber; 583 } 584 throw new ArithmeticException(); 585 } 586 587 @Override 588 public final int intValue( final double aNumber ) { 589 if (DOWN.doubleValue(aNumber) == aNumber) { 590 return DOWN.intValue(aNumber); 591 } 592 throw new ArithmeticException(); 593 } 594 595 @Override 596 public final int intValue( final float aNumber ) { 597 if (DOWN.doubleValue(aNumber) == aNumber) { 598 return DOWN.intValue(aNumber); 599 } 600 throw new ArithmeticException(); 601 } 602 603 @Override 604 public final long longValue( final double aNumber ) { 605 if (DOWN.doubleValue(aNumber) == aNumber) { 606 return DOWN.longValue(aNumber); 607 } 608 throw new ArithmeticException(); 609 } 610 611 @Override 612 public final long longValue( final float aNumber ) { 613 if (DOWN.doubleValue(aNumber) == aNumber) { 614 return DOWN.longValue(aNumber); 615 } 616 throw new ArithmeticException(); 617 } 618 } 619 620 // ---------- 621 // * Unnecessary 622 // 623 624 private static class Up 625 extends 626 RoundingStrategy 627 { 628 public Up() 629 { 630 } 631 632 @Override 633 public final int getBigDecimalRoundingMode() { 634 return BigDecimal.ROUND_UP; 635 } 636 637 @Override 638 public final RoundingMode getRoundingMode() { 639 return RoundingMode.UP; 640 } 641 642 @Override 643 public final double doubleValue( final double aNumber ) { 644 if (DOWN.doubleValue(aNumber) == aNumber) { 645 return DOWN.doubleValue(aNumber); 646 } 647 if (aNumber < 0.0D) { 648 return DOWN.doubleValue(aNumber - 1.0D); 649 } 650 return DOWN.doubleValue(aNumber + 1.0D); 651 } 652 653 @Override 654 public final int intValue( final double aNumber ) { 655 return (int)this.doubleValue(aNumber); 656 } 657 658 @Override 659 public final int intValue( final float aNumber ) { 660 return (int)this.doubleValue(aNumber); 661 } 662 663 @Override 664 public final long longValue( final double aNumber ) { 665 return (long)this.doubleValue(aNumber); 666 } 667 668 @Override 669 public final long longValue( final float aNumber ) { 670 return (long)this.doubleValue(aNumber); 671 } 672 } 673 674 public static final BigDecimal toUnlimitedDecimal( final double aValue ) { 675 return toUnlimitedDecimal(String.valueOf(aValue)); 676 } 677 678 public static final BigDecimal toUnlimitedDecimal( final float aValue ) { 679 return toUnlimitedDecimal(String.valueOf(aValue)); 680 } 681 682 public static final BigDecimal toUnlimitedDecimal( final String aValue ) { 683 try { 684 final BigDecimal ud = new BigDecimal(aValue); 685 return ud; 686 } catch (final NumberFormatException ex) { 687 } 688 return BigDecimal.ZERO; 689 } 690}