/*--------------------------------------------------------------------------- Decimal encoding sample code (C) Copyright International Business Machines Corporation 2003 All Rights Reserved. This sample code is intended to illustrate encoding of decimal floating-point numbers in binary bit strings, and corresponding decoding. Please see the document "General Decimal Arithmetic" at http://speleotrove.com/decimal for a full description of the encoding formats used. This sample code is experimental, and may contain errors. It is offered on an as-is basis. In particular, this sample code is designed to be illustrative rather than to be an implementation optimised for any particular purpose. Indeed, a number of obvious optimisations are omitted in the interests of maximising clarity. Please send comments, suggestions, and corrections to the author: Dave Clark IBM UK, PO Box 31, Birmingham Road, Warwick CV34 5JL, UK dave_clark@uk.ibm.com --------------------------------------------------------------------------*/ package com.ibm.eou.decimal; import java.util.*; /** * This class provides a set of conditions that can * arise during numeric conversions and arithmetic * operations. * @author Dave Clark, IBM Ease of Use */ public class ArithmeticConditions { private final static int BIT_CLAMPED = 0; private final static int BIT_CONVERSION_SYNTAX = 1; private final static int BIT_DIVISION_BY_ZERO = 2; private final static int BIT_DIVISION_IMPOSSIBLE = 3; private final static int BIT_DIVISION_UNDEFINED = 4; private final static int BIT_INEXACT = 5; private final static int BIT_INSUFFICIENT_STORAGE = 6; private final static int BIT_INVALID_CONTEXT = 7; private final static int BIT_INVALID_OPERATION = 8; private final static int BIT_LOST_DIGITS = 9; private final static int BIT_OVERFLOW = 10; private final static int BIT_ROUNDED = 11; private final static int BIT_SUBNORMAL = 12; private final static int BIT_UNDERFLOW = 13; private final BitSet fConditions = new BitSet(); /** * Create a set of arithmetic conditions. Initially, all * conditions are reset. */ public ArithmeticConditions() { } /** * Return true if the clamped condition is set. The clamped condition indicates * that an exponent was adjusted to bring it into the range of encodable * values. If the coefficient was non-zero, it will have been adjusted * correspondingly by adding trailing zeroes. */ public boolean isClamped() { return fConditions.get(BIT_CLAMPED); } /** * Set the clamped condition. * @see #isClamped() */ public void setClamped() { fConditions.set(BIT_CLAMPED); } /** * Return true if the conversion syntax condition is set. */ public boolean isConversionSyntax() { return fConditions.get(BIT_CONVERSION_SYNTAX); } /** * Set the conversion syntax condition. * @see #isConversionSyntax() */ public void setConversionSyntax() { fConditions.set(BIT_CONVERSION_SYNTAX); } /** * Return true if the division by zero condition is set. */ public boolean isDivisionByZero() { return fConditions.get(BIT_DIVISION_BY_ZERO); } /** * Set the division by zero condition. * @see #isDivisionByZero() */ public void setDivisionByZero() { fConditions.set(BIT_DIVISION_BY_ZERO); } /** * Return true if the division impossible condition is set. */ public boolean isDivisionImpossible() { return fConditions.get(BIT_DIVISION_IMPOSSIBLE); } /** * Set the division impossible condition. * @see #isDivisionImpossible() */ public void setDivisionImpossible() { fConditions.set(BIT_DIVISION_IMPOSSIBLE); } /** * Return true if the division undefined condition is set. */ public boolean isDivisionUndefined() { return fConditions.get(BIT_DIVISION_UNDEFINED); } /** * Set the division undefined condition. * @see #isDivisionUndefined() */ public void setDivisionUndefined() { fConditions.set(BIT_DIVISION_UNDEFINED); } /** * Return true if the inexact condition is set. The inexact condition indicates * that an adjustment that was necessary to make a number encodable * has resulted in an encoding that is not exactly the original number. * This may occur because of rounding of non-zero trailing digits, or * because of overflows or underflows to infinities or zeroes. */ public boolean isInexact() { return fConditions.get(BIT_INEXACT); } /** * Set the inexact condition. * @see #isInexact() */ public void setInexact() { fConditions.set(BIT_INEXACT); } /** * Return true if the insufficient storage condition is set. */ public boolean isInsufficientStorage() { return fConditions.get(BIT_INSUFFICIENT_STORAGE); } /** * Set the insufficient storage condition. * @see #isInsufficientStorage() */ public void setInsufficientStorage() { fConditions.set(BIT_INSUFFICIENT_STORAGE); } /** * Return true if the invalid context condition is set. */ public boolean isInvalidContext() { return fConditions.get(BIT_INVALID_CONTEXT); } /** * Set the invalid context condition. * @see #isInvalidContext() */ public void setInvalidContext() { fConditions.set(BIT_INVALID_CONTEXT); } /** * Return true if the invalid operation condition is set. */ public boolean isInvalidOperation() { return fConditions.get(BIT_INVALID_OPERATION); } /** * Set the invalid operation condition. * @see #isInvalidOperation() */ public void setInvalidOperation() { fConditions.set(BIT_INVALID_OPERATION); } /** * Return true if the lost digits condition is set. */ public boolean isLostDigits() { return fConditions.get(BIT_LOST_DIGITS); } /** * Set the lost digits condition. * @see #isLostDigits() */ public void setLostDigits() { fConditions.set(BIT_LOST_DIGITS); } /** * Return true if the overflow condition is set. The overflow condition indicates * that the magnitude of a number was greater than or equal to the normal * range upper threshold, possibly after applying necessary rounding. * When the overflow condition is set, the resultant encoding will generally * be an infinity, although certain values near to the normal range upper * threshold may combine with certain rounding methods to set the overflow * condition while still yielding a finite encoding. */ public boolean isOverflow() { return fConditions.get(BIT_OVERFLOW); } /** * Set the overflow condition. * @see #isOverflow */ public void setOverflow() { fConditions.set(BIT_OVERFLOW); } /** * Return true if the rounded condition is set. The rounded condition indicates * that a coefficient was shortened to bring it into the range of encodable * coefficient lengths. The exponent will also have been adjusted * correspondingly. If there were trailing zeroes on the original coefficient, * it is possible for the rounded condition to be set without the resultant * encoding being inexact. * */ public boolean isRounded() { return fConditions.get(BIT_ROUNDED); } /** * Set the rounded condition. * @see #isRounded() */ public void setRounded() { fConditions.set(BIT_ROUNDED); } /** * Return true if the subnormal condition is set. The subnormal condition indicates * that the number was finite and non-zero and had a magnitude less than * the normal range lower threshold. Some subnormal numbers can be * accommodated in the encoding, although there is less precision available * than for numbers in the normal range. If the number can be accommodated * exactly in this way, the subnormal condition will be set. If * rounding had to be applied, or if the number was out of the range of * encodable subnormal numbers, then the {@link #isInexact() inexact} * condition will be set, along with the {@link #isUnderflow() underflow} condition. * Note that the resultant encoding may not be a subnormal number when * the subnormal condition is set. */ public boolean isSubnormal() { return fConditions.get(BIT_SUBNORMAL); } /** * Set the subnormal condition. * @see #isSubnormal() */ public void setSubnormal() { fConditions.set(BIT_SUBNORMAL); } /** * Return true if the underflow condition is set. The underflow condition generally * indicates that the magnitude of a number is less than the normal range * lower threshold and could not be exactly encoded. The resultant encoding * may be a zero or one of the small-magnitude finite encodings described * as {@link #isSubnormal subnormal}, although certain values near to the * normal range lower threshold may combine with certain rounding methods * to set the underflow condition while still yielding a finite encoding in the * normal range. */ public boolean isUnderflow() { return fConditions.get(BIT_UNDERFLOW); } /** * Set the underflow condition. * @see #isUnderflow() */ public void setUnderflow() { fConditions.set(BIT_UNDERFLOW); } /** * Set all the conditions which are set in the * specified set of conditions. */ public void setAll(final ArithmeticConditions conditions) { fConditions.or(conditions.fConditions); } /** * Clear all the conditions. */ public void resetAll() { fConditions.clear(BIT_CLAMPED); fConditions.clear(BIT_CONVERSION_SYNTAX); fConditions.clear(BIT_DIVISION_BY_ZERO); fConditions.clear(BIT_DIVISION_IMPOSSIBLE); fConditions.clear(BIT_DIVISION_UNDEFINED); fConditions.clear(BIT_INEXACT); fConditions.clear(BIT_INSUFFICIENT_STORAGE); fConditions.clear(BIT_INVALID_CONTEXT); fConditions.clear(BIT_INVALID_OPERATION); fConditions.clear(BIT_LOST_DIGITS); fConditions.clear(BIT_OVERFLOW); fConditions.clear(BIT_ROUNDED); fConditions.clear(BIT_SUBNORMAL); fConditions.clear(BIT_UNDERFLOW); } /** * Represent the set conditions as a compact string, using a single * letter for each set condition. The letters used are as follows: * * If no conditions are set, the string "-" is returned. */ public String toCompactString() { // fConditions.size() is an upper bound for the number of conditions currently set final StringBuffer result = new StringBuffer(fConditions.size()); if (isClamped()) result.append('C'); if (isConversionSyntax()) result.append('X'); if (isDivisionByZero()) result.append('Z'); if (isDivisionImpossible()) result.append('V'); if (isDivisionUndefined()) result.append('N'); if (isInexact()) result.append('I'); if (isInsufficientStorage()) result.append('G'); if (isInvalidContext()) result.append('T'); if (isInvalidOperation()) result.append('P'); if (isLostDigits()) result.append('L'); if (isOverflow()) result.append('O'); if (isRounded()) result.append('R'); if (isSubnormal()) result.append('S'); if (isUnderflow()) result.append('U'); return (result.length() == 0) ? "-" : result.toString(); //$NON-NLS-1$ } /** * Return true if the conditions all match. */ public boolean equals(final Object other) { if (other instanceof ArithmeticConditions) return fConditions.equals(((ArithmeticConditions)other).fConditions); else return false; } /** * Return a hash code which will be equal for objects * that compare equal, and will preferably be different * for objects that compare unequal. */ public int hashCode() { // since we base equality on the BitSet equality, // we base our hashcode on the BitSet hashcode return 17 * fConditions.hashCode(); } }