view src/decimal/context.d @ 8:c991b9fde45c

added rounding (partially implemented)
author Paul (paul.d.anderson@comcast.net)
date Tue, 23 Mar 2010 21:54:23 -0700
parents abf9d7974708
children
line wrap: on
line source

/** 
 * A D programming language implementation of the 
 * General Decimal Arithmetic Specification, 
 * Version 1.70, (25 March 2009).
 *
 * by Paul D. Anderson
 *
 * Boost Software License - Version 1.0 - August 17th, 2003
 *
 * Permission is hereby granted, free of charge, to any person or organization
 * obtaining a copy of the software and accompanying documentation covered by
 * this license (the "Software") to use, reproduce, display, distribute,
 * execute, and transmit the Software, and to prepare derivative works of the
 * Software, and to permit third-parties to whom the Software is furnished to
 * do so, all subject to the following:
 *
 * The copyright notices in the Software and this entire statement, including
 * the above license grant, this restriction and the following disclaimer,
 * must be included in all copies of the Software, in whole or in part, and
 * all derivative works of the Software, unless such copies or derivative
 * works are solely in the form of machine-executable object code generated by
 * a source language processor.
 * 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
 * SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
 * FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 * DEALINGS IN THE SOFTWARE.
**/

module decimal.context;

import decimal.decimal;
import std.string;

//--------------------------
//
// DecimalContext struct
//
//--------------------------

/**
 * Enumeration of available rounding modes.
 */
public enum Rounding {
	HALF_EVEN,
	HALF_DOWN,
	HALF_UP,
	DOWN,
	UP,
	FLOOR,
	CEILING,
}


// context flags
public enum : ubyte {
 	 CLAMPED           = 0x01,
 	 DIVISION_BY_ZERO  = 0x02,
 	 INEXACT           = 0x04,
 	 INVALID_OPERATION = 0x08,
 	 OVERFLOW          = 0x10,
 	 ROUNDED           = 0x20,
 	 SUBNORMAL         = 0x40,
 	 UNDERFLOW         = 0x80
}
	
/+public:
 	static immutable ubyte CLAMPED           = 0x01;
 	static immutable ubyte DIVISION_BY_ZERO  = 0x02;
 	static immutable ubyte INEXACT           = 0x04;
 	static immutable ubyte INVALID_OPERATION = 0x08;
 	static immutable ubyte OVERFLOW          = 0x10;
 	static immutable ubyte ROUNDED           = 0x20;
 	static immutable ubyte SUBNORMAL         = 0x40;
 	static immutable ubyte UNDERFLOW         = 0x80;+/

/**
 * Context for Decimal mathematic operations
 */
public struct DecimalContext {
	public:
		Rounding mode = Rounding.HALF_EVEN;
		uint precision = 9;
		ubyte traps;
		ubyte flags;
		int eMin = -98;
		int eMax = 99;
	
	const int eTiny() {
		return eMin - (precision - 1);
	}
	
	/// Returns the number of decimal digits in this context.
	const uint dig() {
		return precision;
	}
	
	/// returns the smallest available increment to one in this context
	const Decimal epsilon() {
		return Decimal(1,-precision);
	}
		
	/// Returns the number of binary digits in this context.
	const int mant_dig() {
		return cast(int)(precision/LOG2);
	}

	const int min_exp() {
		return cast(int)(eMin/LOG2);
	}
	
	const int max_exp() {
		return cast(int)(eMax/LOG2);
	}
	
	const int min_10_exp() {
		return eMin;
	}
	
	const int max_10_exp() {
		return eMax;
	}
	
	/// Returns the maximum representable normal value in the current context.
	// TODO: Replace this formula with a single execution when precision or eMax is changed.
	const Decimal max() {
		string cstr = "9." ~ repeat("9", precision-1) ~ "E" ~ format("%d", eMax);
		return Decimal(cstr);
	}
	
	// Returns the minimum representable normal value in the current context.
	const Decimal min_normal() {
		return Decimal(1, eMin);
	}
	
	// Returns the minimum representable subnormal value in the current context.
	const Decimal min() {
		return Decimal(1, eTiny);
	}
	
/+	public const int getPrecision() {
		return precision;
	}
	
	public void setPrecision(int precision) {
		this.precision = precision;
	}+/
	
	const void setFlag(const ubyte flag, const bool value = true) {
		if (value) {
		 context.flags |= flag; 
		}
		else {
		  context.flags &= !flag;
        }
	}
	
	public bool getFlag(const ubyte flag) {
		return (context.flags & flag) == flag;
	}
	
	public void clearFlags() {
		context.flags = 0;
	}
	

};	// end struct DecimalContext

public:
	// default context
	immutable DecimalContext DEFAULT_CONTEXT = DecimalContext();
	
private:
	// context stack
struct ContextStack {
	private:
		DecimalContext[] stack = [ DEFAULT_CONTEXT ];
		uint capacity = 1;
		uint count = 1;

	public void push() {
		if (count >= capacity) {
			capacity *= 2;
			stack.length = capacity;
		}
		count++;
		stack[count-1] = context;
	}
	
	public void pop() {
		if (count == 0) {
			push();
		}
		if (count == 1) {
			context = stack[0];
		}
		else {
			count--;
			context = stack[count-1];
		}
	}
	
} // end struct ContextStack

//--------------------------
//
// Emd of DecimalContext struct
//
//--------------------------