diff options
Diffstat (limited to 'src/tool/moneycount')
-rw-r--r-- | src/tool/moneycount/Makefile | 5 | ||||
-rw-r--r-- | src/tool/moneycount/inf.cpp | 1482 | ||||
-rw-r--r-- | src/tool/moneycount/inf.hpp | 228 | ||||
-rw-r--r-- | src/tool/moneycount/main.cpp | 42 | ||||
-rw-r--r-- | src/tool/moneycount/portability_exceptions.hpp | 33 | ||||
-rw-r--r-- | src/tool/moneycount/portability_fixes.cpp | 39 | ||||
-rw-r--r-- | src/tool/moneycount/portability_fixes.hpp | 127 |
7 files changed, 1941 insertions, 15 deletions
diff --git a/src/tool/moneycount/Makefile b/src/tool/moneycount/Makefile index 27cd98e..e7b7022 100644 --- a/src/tool/moneycount/Makefile +++ b/src/tool/moneycount/Makefile @@ -1,13 +1,14 @@ all: moneycount -OBJECTS = main.o athena_text.o +OBJECTS = main.o athena_text.o inf.o portability_fixes.o CPP = g++ moneycount: $(OBJECTS) $(CPP) -o $@ $(OBJECTS) $(COMMON_OBJS) $(LIBS) main.o: main.cpp athena_text.o: athena_text.cpp athena_text.h - +inf.o: inf.cpp inf.hpp +portability_fixes.o: portability_fixes.cpp portability_fixes.hpp portability_exceptions.hpp clean: rm -f *.o moneycount diff --git a/src/tool/moneycount/inf.cpp b/src/tool/moneycount/inf.cpp new file mode 100644 index 0000000..80b0475 --- /dev/null +++ b/src/tool/moneycount/inf.cpp @@ -0,0 +1,1482 @@ +////////////////////////////////////////////////////////////////////////////////
+
+// Author: Andy Rushton
+// Copyright: (c) Southampton University 1999-2004
+// (c) Andy Rushton 2004-2009
+// License: BSD License, see ../docs/license.html
+
+// The integer is represented as a sequence of bytes. They are stored such that
+// element 0 is the lsB, which makes sense when seen as an integer offset but
+// is counter-intuitive when you think that a string is usually read from left
+// to right, 0 to size-1, in which case the lsB is on the *left*.
+
+// This solution is compatible with 32-bit and 64-bit machines with either
+// little-endian or big-endian representations of integers.
+
+// Problem: I'm using std::string, which is an array of char. However, char is
+// not well-defined - it could be signed or unsigned.
+
+// In fact, there's no requirement for a char to even be one byte - it can be
+// any size of one byte or more. However, it's just impossible to make any
+// progress with that naffness (thanks to the C non-standardisation committee)
+// and the practice is that char on every platform/compiler I've ever come
+// across is that char = byte.
+
+// The algorithms here use unsigned char to represent bit-patterns so I have to
+// be careful to type-cast from char to unsigned char a lot. I use a typedef to
+// make life easier.
+
+////////////////////////////////////////////////////////////////////////////////
+#include "inf.hpp"
+#include <ctype.h>
+////////////////////////////////////////////////////////////////////////////////
+
+namespace stlplus
+{
+
+ ////////////////////////////////////////////////////////////////////////////////
+ // choose a sensible C type for a byte
+
+ typedef unsigned char byte;
+
+ ////////////////////////////////////////////////////////////////////////////////
+ // local functions
+
+ // removes leading bytes that don't contribute to the value to create the minimum string representation
+ static void reduce_string(std::string& data)
+ {
+ while(data.size() > 1 &&
+ ((byte(data[data.size()-1]) == byte(0) && byte(data[data.size()-2]) < byte(128)) ||
+ (byte(data[data.size()-1]) == byte(255) && byte(data[data.size()-2]) >= byte(128))))
+ {
+ data.erase(data.end()-1);
+ }
+ }
+
+ // generic implementations of type conversions from integer type to internal representation
+ // data: integer value for conversion
+ // result: internal representation
+
+ template <typename T>
+ static void convert_from_signed(const T& data, std::string& result)
+ {
+ result.erase();
+ bool lsb_first = little_endian();
+ byte* address = (byte*)&data;
+ for (size_t i = 0; i < sizeof(T); i++)
+ {
+ size_t offset = (lsb_first ? i : (sizeof(T) - i - 1));
+ result.append(1,address[offset]);
+ }
+ reduce_string(result);
+ }
+
+ template <typename T>
+ static void convert_from_unsigned(const T& data, std::string& result)
+ {
+ result.erase();
+ bool lsb_first = little_endian();
+ byte* address = (byte*)&data;
+ for (size_t i = 0; i < sizeof(T); i++)
+ {
+ size_t offset = (lsb_first ? i : (sizeof(T) - i - 1));
+ result.append(1,address[offset]);
+ }
+ // inf is signed - so there is a possible extra sign bit to add
+ result.append(1,std::string::value_type(0));
+ reduce_string(result);
+ }
+
+ // generic implementations of type conversions from internal representation to an integer type
+ // data : string representation of integer
+ // result: integer result of conversion
+ // return: flag indicating success - false = overflow
+
+ template <class T>
+ bool convert_to_signed(const std::string& data, T& result)
+ {
+ bool lsb_first = little_endian();
+ byte* address = (byte*)&result;
+ for (size_t i = 0; i < sizeof(T); i++)
+ {
+ size_t offset = lsb_first ? i : (sizeof(T) - i - 1);
+ if (i < data.size())
+ address[offset] = byte(data[i]);
+ else if (data.empty() || (byte(data[data.size()-1]) < byte(128)))
+ address[offset] = byte(0);
+ else
+ address[offset] = byte(255);
+ }
+ return data.size() <= sizeof(T);
+ }
+
+ template <class T>
+ bool convert_to_unsigned(const std::string& data, T& result)
+ {
+ bool lsb_first = little_endian();
+ byte* address = (byte*)&result;
+ for (size_t i = 0; i < sizeof(T); i++)
+ {
+ size_t offset = lsb_first ? i : (sizeof(T) - i - 1);
+ if (i < data.size())
+ address[offset] = byte(data[i]);
+ else
+ address[offset] = byte(0);
+ }
+ return data.size() <= sizeof(T);
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ // Conversions to string
+
+ static char to_char [] = "0123456789abcdefghijklmnopqrstuvwxyz";
+ static int from_char [] =
+ {
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1,
+ -1, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
+ 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, -1, -1, -1, -1, -1,
+ -1, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
+ 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
+ };
+
+ static void convert_to_string(const stlplus::inf& data, std::string& result, unsigned radix = 10)
+ throw(std::invalid_argument)
+ {
+ // only support the C-style radixes plus 0b for binary
+ if (radix != 2 && radix != 8 && radix != 10 && radix != 16)
+ throw std::invalid_argument("invalid radix value");
+ inf local_i = data;
+ // untangle all the options
+ bool binary = radix == 2;
+ bool octal = radix == 8;
+ bool hex = radix == 16;
+ // the C representations for binary, octal and hex use 2's-complement representation
+ // all other represenations use sign-magnitude
+ if (hex || octal || binary)
+ {
+ // bit-pattern representation
+ // this is the binary representation optionally shown in octal or hex
+ // first generate the binary by masking the bits
+ for (unsigned j = local_i.bits(); j--; )
+ result += (local_i.bit(j) ? '1' : '0');
+ // the result is now the full width of the type - e.g. int will give a 32-bit result
+ // now interpret this as either binary, octal or hex and add the prefix
+ if (binary)
+ {
+ // trim down to the smallest string that preserves the value
+ while (true)
+ {
+ // do not trim to less than 1 bit (sign only)
+ if (result.size() <= 1) break;
+ // only trim if it doesn't change the sign and therefore the value
+ if (result[0] != result[1]) break;
+ result.erase(0,1);
+ }
+ // add the prefix
+ result.insert((std::string::size_type)0, "0b");
+ }
+ else if (octal)
+ {
+ // the result is currently binary
+ // trim down to the smallest string that preserves the value
+ while (true)
+ {
+ // do not trim to less than 2 bits (sign plus 1-bit magnitude)
+ if (result.size() <= 2) break;
+ // only trim if it doesn't change the sign and therefore the value
+ if (result[0] != result[1]) break;
+ result.erase(0,1);
+ }
+ // also ensure that the binary is a multiple of 3 bits to make the conversion to octal easier
+ while (result.size() % 3 != 0)
+ result.insert((std::string::size_type)0, 1, result[0]);
+ // now convert to octal
+ std::string octal_result;
+ for (unsigned i = 0; i < result.size()/3; i++)
+ {
+ // yuck - ugly or what?
+ if (result[i*3] == '0')
+ {
+ if (result[i*3+1] == '0')
+ {
+ if (result[i*3+2] == '0')
+ octal_result += '0';
+ else
+ octal_result += '1';
+ }
+ else
+ {
+ if (result[i*3+2] == '0')
+ octal_result += '2';
+ else
+ octal_result += '3';
+ }
+ }
+ else
+ {
+ if (result[i*3+1] == '0')
+ {
+ if (result[i*3+2] == '0')
+ octal_result += '4';
+ else
+ octal_result += '5';
+ }
+ else
+ {
+ if (result[i*3+2] == '0')
+ octal_result += '6';
+ else
+ octal_result += '7';
+ }
+ }
+ }
+ result = octal_result;
+ // add the prefix
+ result.insert((std::string::size_type)0, "0");
+ }
+ else
+ {
+ // similar to octal
+ while (true)
+ {
+ // do not trim to less than 2 bits (sign plus 1-bit magnitude)
+ if (result.size() <= 2) break;
+ // only trim if it doesn't change the sign and therefore the value
+ if (result[0] != result[1]) break;
+ result.erase(0,1);
+ }
+ // pad to a multiple of 4 characters
+ while (result.size() % 4 != 0)
+ result.insert((std::string::size_type)0, 1, result[0]);
+ // now convert to hex
+ std::string hex_result;
+ for (unsigned i = 0; i < result.size()/4; i++)
+ {
+ // yuck - ugly or what?
+ if (result[i*4] == '0')
+ {
+ if (result[i*4+1] == '0')
+ {
+ if (result[i*4+2] == '0')
+ {
+ if (result[i*4+3] == '0')
+ hex_result += '0';
+ else
+ hex_result += '1';
+ }
+ else
+ {
+ if (result[i*4+3] == '0')
+ hex_result += '2';
+ else
+ hex_result += '3';
+ }
+ }
+ else
+ {
+ if (result[i*4+2] == '0')
+ {
+ if (result[i*4+3] == '0')
+ hex_result += '4';
+ else
+ hex_result += '5';
+ }
+ else
+ {
+ if (result[i*4+3] == '0')
+ hex_result += '6';
+ else
+ hex_result += '7';
+ }
+ }
+ }
+ else
+ {
+ if (result[i*4+1] == '0')
+ {
+ if (result[i*4+2] == '0')
+ {
+ if (result[i*4+3] == '0')
+ hex_result += '8';
+ else
+ hex_result += '9';
+ }
+ else
+ {
+ if (result[i*4+3] == '0')
+ hex_result += 'a';
+ else
+ hex_result += 'b';
+ }
+ }
+ else
+ {
+ if (result[i*4+2] == '0')
+ {
+ if (result[i*4+3] == '0')
+ hex_result += 'c';
+ else
+ hex_result += 'd';
+ }
+ else
+ {
+ if (result[i*4+3] == '0')
+ hex_result += 'e';
+ else
+ hex_result += 'f';
+ }
+ }
+ }
+ }
+ result = hex_result;
+ // add the prefix
+ result.insert((std::string::size_type)0, "0x");
+ }
+ }
+ else
+ {
+ // convert to sign-magnitude
+ // the representation is:
+ // [sign]magnitude
+ bool negative = local_i.negative();
+ local_i.abs();
+ // create a representation of the magnitude by successive division
+ inf inf_radix(radix);
+ do
+ {
+ std::pair<inf,inf> divided = local_i.divide(inf_radix);
+ unsigned remainder = divided.second.to_unsigned();
+ char digit = to_char[remainder];
+ result.insert((std::string::size_type)0, 1, digit);
+ local_i = divided.first;
+ }
+ while(!local_i.zero());
+ // add the prefixes
+ // add a sign only for negative values
+ if (negative)
+ result.insert((std::string::size_type)0, 1, '-');
+ }
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ // Conversions FROM string
+
+ void convert_from_string(const std::string& str, inf& result, unsigned radix = 10) throw(std::invalid_argument)
+ {
+ result = 0;
+ // only support the C-style radixes plus 0b for binary
+ // a radix of 0 means deduce the radix from the input - assume 10
+ if (radix != 0 && radix != 2 && radix != 8 && radix != 10 && radix != 16)
+ throw std::invalid_argument("invalid radix value");
+ unsigned i = 0;
+ // the radix passed as a parameter is just the default - it can be
+ // overridden by the C prefix
+ // Note: a leading zero is the C-style prefix for octal - I only make this
+ // override the default when the default radix is not specified
+ // first check for a C-style prefix
+ bool c_style = false;
+ if (i < str.size() && str[i] == '0')
+ {
+ // binary or hex
+ if (i+1 < str.size() && tolower(str[i+1]) == 'x')
+ {
+ c_style = true;
+ radix = 16;
+ i += 2;
+ }
+ else if (i+1 < str.size() && tolower(str[i+1]) == 'b')
+ {
+ c_style = true;
+ radix = 2;
+ i += 2;
+ }
+ else if (radix == 0)
+ {
+ c_style = true;
+ radix = 8;
+ i += 1;
+ }
+ }
+ if (radix == 0)
+ radix = 10;
+ if (c_style)
+ {
+ // the C style formats are bit patterns not integer values - these need
+ // to be sign-extended to get the right value
+ std::string binary;
+ if (radix == 2)
+ {
+ for (unsigned j = i; j < str.size(); j++)
+ {
+ switch(str[j])
+ {
+ case '0':
+ binary += '0';
+ break;
+ case '1':
+ binary += '1';
+ break;
+ default:
+ throw std::invalid_argument("invalid binary character in string " + str);
+ }
+ }
+ }
+ else if (radix == 8)
+ {
+ for (unsigned j = i; j < str.size(); j++)
+ {
+ switch(str[j])
+ {
+ case '0':
+ binary += "000";
+ break;
+ case '1':
+ binary += "001";
+ break;
+ case '2':
+ binary += "010";
+ break;
+ case '3':
+ binary += "011";
+ break;
+ case '4':
+ binary += "100";
+ break;
+ case '5':
+ binary += "101";
+ break;
+ case '6':
+ binary += "110";
+ break;
+ case '7':
+ binary += "111";
+ break;
+ default:
+ throw std::invalid_argument("invalid octal character in string " + str);
+ }
+ }
+ }
+ else
+ {
+ for (unsigned j = i; j < str.size(); j++)
+ {
+ switch(tolower(str[j]))
+ {
+ case '0':
+ binary += "0000";
+ break;
+ case '1':
+ binary += "0001";
+ break;
+ case '2':
+ binary += "0010";
+ break;
+ case '3':
+ binary += "0011";
+ break;
+ case '4':
+ binary += "0100";
+ break;
+ case '5':
+ binary += "0101";
+ break;
+ case '6':
+ binary += "0110";
+ break;
+ case '7':
+ binary += "0111";
+ break;
+ case '8':
+ binary += "1000";
+ break;
+ case '9':
+ binary += "1001";
+ break;
+ case 'a':
+ binary += "1010";
+ break;
+ case 'b':
+ binary += "1011";
+ break;
+ case 'c':
+ binary += "1100";
+ break;
+ case 'd':
+ binary += "1101";
+ break;
+ case 'e':
+ binary += "1110";
+ break;
+ case 'f':
+ binary += "1111";
+ break;
+ default:
+ throw std::invalid_argument("invalid hex character in string " + str);
+ }
+ }
+ }
+ // now convert the value
+ result.resize(binary.size());
+ for (unsigned j = 0; j < binary.size(); j++)
+ result.preset(binary.size() - j - 1, binary[j] == '1');
+ }
+ else
+ {
+ // sign-magnitude representation
+ // now scan for a sign and find whether this is a negative number
+ bool negative = false;
+ if (i < str.size())
+ {
+ switch (str[i])
+ {
+ case '-':
+ negative = true;
+ i++;
+ break;
+ case '+':
+ i++;
+ break;
+ }
+ }
+ for (; i < str.size(); i++)
+ {
+ result *= inf(radix);
+ unsigned char ascii = (unsigned char)str[i];
+ int ch = from_char[ascii] ;
+ if (ch == -1)
+ throw std::invalid_argument("invalid decimal character in string " + str);
+ result += inf(ch);
+ }
+ if (negative)
+ result.negate();
+ }
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ // constructors - mostly implemented in terms of the assignment operators
+
+ inf::inf(void)
+ {
+ // void constructor initialises to zero - represented as a single-byte value containing zero
+ m_data.append(1,std::string::value_type(0));
+ }
+
+ inf::inf(short r)
+ {
+ operator=(r);
+ }
+
+ inf::inf(unsigned short r)
+ {
+ operator=(r);
+ }
+
+ inf::inf(int r)
+ {
+ operator=(r);
+ }
+
+ inf::inf(unsigned r)
+ {
+ operator=(r);
+ }
+
+ inf::inf(long r)
+ {
+ operator=(r);
+ }
+
+ inf::inf(unsigned long r)
+ {
+ operator=(r);
+ }
+
+ inf::inf (const std::string& r) throw(std::invalid_argument)
+ {
+ operator=(r);
+ }
+
+ inf::inf(const inf& r)
+ {
+#ifdef __BORLANDC__
+ // work round bug in Borland compiler - copy constructor fails if string
+ // contains null characters, so do my own copy
+ for (unsigned i = 0; i < r.m_data.size(); i++)
+ m_data += r.m_data[i];
+#else
+ m_data = r.m_data;
+#endif
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+
+ inf::~inf(void)
+ {
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ // assignments convert from iteger types to internal representation
+
+ inf& inf::operator = (short r)
+ {
+ convert_from_signed(r, m_data);
+ return *this;
+ }
+
+ inf& inf::operator = (unsigned short r)
+ {
+ convert_from_unsigned(r, m_data);
+ return *this;
+ }
+
+ inf& inf::operator = (int r)
+ {
+ convert_from_signed(r, m_data);
+ return *this;
+ }
+
+ inf& inf::operator = (unsigned r)
+ {
+ convert_from_unsigned(r, m_data);
+ return *this;
+ }
+
+ inf& inf::operator = (long r)
+ {
+ convert_from_signed(r, m_data);
+ return *this;
+ }
+
+ inf& inf::operator = (unsigned long r)
+ {
+ convert_from_unsigned(r, m_data);
+ return *this;
+ }
+
+ inf& inf::operator = (const std::string& r) throw(std::invalid_argument)
+ {
+ convert_from_string(r, *this);
+ return *this;
+ }
+
+ inf& inf::operator = (const inf& r)
+ {
+ m_data = r.m_data;
+ return *this;
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+
+ short inf::to_short(bool truncate) const throw(std::overflow_error)
+ {
+ short result = 0;
+ if (!convert_to_signed(m_data, result))
+ if (!truncate)
+ throw std::overflow_error("stlplus::inf::to_short");
+ return result;
+ }
+
+ unsigned short inf::to_unsigned_short(bool truncate) const throw(std::overflow_error)
+ {
+ unsigned short result = 0;
+ if (!convert_to_unsigned(m_data, result))
+ if (!truncate)
+ throw std::overflow_error("stlplus::inf::to_unsigned_short");
+ return result;
+ }
+
+ int inf::to_int(bool truncate) const throw(std::overflow_error)
+ {
+ int result = 0;
+ if (!convert_to_signed(m_data, result))
+ if (!truncate)
+ throw std::overflow_error("stlplus::inf::to_int");
+ return result;
+ }
+
+ unsigned inf::to_unsigned(bool truncate) const throw(std::overflow_error)
+ {
+ unsigned result = 0;
+ if (!convert_to_unsigned(m_data, result))
+ if (!truncate)
+ throw std::overflow_error("stlplus::inf::to_unsigned");
+ return result;
+ }
+
+ long inf::to_long(bool truncate) const throw(std::overflow_error)
+ {
+ long result = 0;
+ if (!convert_to_signed(m_data, result))
+ if (!truncate)
+ throw std::overflow_error("stlplus::inf::to_long");
+ return result;
+ }
+
+ unsigned long inf::to_unsigned_long(bool truncate) const throw(std::overflow_error)
+ {
+ unsigned long result = 0;
+ if (!convert_to_unsigned(m_data, result))
+ if (!truncate)
+ throw std::overflow_error("stlplus::inf::to_unsigned_long");
+ return result;
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ // resize the inf regardless of the data
+
+ void inf::resize(unsigned bits)
+ {
+ if (bits == 0) bits = 1;
+ unsigned bytes = (bits+7)/8;
+ byte extend = negative() ? byte(255) : byte (0);
+ while(bytes > m_data.size())
+ m_data.append(1,extend);
+ }
+
+ // reduce the bit count to the minimum needed to preserve the value
+
+ void inf::reduce(void)
+ {
+ reduce_string(m_data);
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ // the number of significant bits in the number
+
+ unsigned inf::bits (void) const
+ {
+ // The number of significant bits in the integer value - this is the number
+ // of indexable bits less any redundant sign bits at the msb
+ // This does not assume that the inf has been reduced to its minimum form
+ unsigned result = indexable_bits();
+ bool sign = bit(result-1);
+ while (result > 1 && (sign == bit(result-2)))
+ result--;
+ return result;
+ }
+
+ unsigned inf::size(void) const
+ {
+ return bits();
+ }
+
+ unsigned inf::indexable_bits (void) const
+ {
+ return 8 * unsigned(m_data.size());
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ // bitwise operations
+
+ bool inf::bit (unsigned index) const throw(std::out_of_range)
+ {
+ if (index >= indexable_bits())
+ throw std::out_of_range(std::string("stlplus::inf::bit"));
+ // first split the offset into byte offset and bit offset
+ unsigned byte_offset = index/8;
+ unsigned bit_offset = index%8;
+ return (byte(m_data[byte_offset]) & (byte(1) << bit_offset)) != 0;
+ }
+
+ bool inf::operator [] (unsigned index) const throw(std::out_of_range)
+ {
+ return bit(index);
+ }
+
+ void inf::set (unsigned index) throw(std::out_of_range)
+ {
+ if (index >= indexable_bits())
+ throw std::out_of_range(std::string("stlplus::inf::set"));
+ // first split the offset into byte offset and bit offset
+ unsigned byte_offset = index/8;
+ unsigned bit_offset = index%8;
+ m_data[byte_offset] |= (byte(1) << bit_offset);
+ }
+
+ void inf::clear (unsigned index) throw(std::out_of_range)
+ {
+ if (index >= indexable_bits())
+ throw std::out_of_range(std::string("stlplus::inf::clear"));
+ // first split the offset into byte offset and bit offset
+ unsigned byte_offset = index/8;
+ unsigned bit_offset = index%8;
+ m_data[byte_offset] &= (~(byte(1) << bit_offset));
+ }
+
+ void inf::preset (unsigned index, bool value) throw(std::out_of_range)
+ {
+ if (value)
+ set(index);
+ else
+ clear(index);
+ }
+
+ inf inf::slice(unsigned low, unsigned high) const throw(std::out_of_range)
+ {
+ if (low >= indexable_bits())
+ throw std::out_of_range(std::string("stlplus::inf::slice: low index"));
+ if (high >= indexable_bits())
+ throw std::out_of_range(std::string("stlplus::inf::slice: high index"));
+ inf result;
+ if (high >= low)
+ {
+ // create a result the right size and filled with sign bits
+ std::string::size_type result_size = (high-low+1+7)/8;
+ result.m_data.erase();
+ byte extend = bit(high) ? byte(255) : byte (0);
+ while (result.m_data.size() < result_size)
+ result.m_data.append(1,extend);
+ // now set the relevant bits
+ for (unsigned i = low; i <= high; i++)
+ result.preset(i-low, bit(i));
+ }
+ return result;
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ // testing operations
+
+ bool inf::negative (void) const
+ {
+ return bit(indexable_bits()-1);
+ }
+
+ bool inf::natural (void) const
+ {
+ return !negative();
+ }
+
+ bool inf::positive (void) const
+ {
+ return natural() && !zero();
+ }
+
+ bool inf::zero (void) const
+ {
+ for (std::string::size_type i = 0; i < m_data.size(); i++)
+ if (m_data[i] != 0)
+ return false;
+ return true;
+ }
+
+ bool inf::non_zero (void) const
+ {
+ return !zero();
+ }
+
+ bool inf::operator ! (void) const
+ {
+ return zero();
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ // comparison operators
+
+ bool inf::operator == (const inf& r) const
+ {
+ // Two infs are equal if they are numerically equal, even if they are
+ // different sizes (i.e. they could be non-reduced values).
+ // This makes life a little more complicated than if I could assume that values were reduced.
+ byte l_extend = negative() ? byte(255) : byte (0);
+ byte r_extend = r.negative() ? byte(255) : byte (0);
+ std::string::size_type bytes = maximum(m_data.size(),r.m_data.size());
+ for (std::string::size_type i = bytes; i--; )
+ {
+ byte l_byte = (i < m_data.size() ? byte(m_data[i]) : l_extend);
+ byte r_byte = (i < r.m_data.size() ? byte(r.m_data[i]) : r_extend);
+ if (l_byte != r_byte)
+ return false;
+ }
+ return true;
+ }
+
+ bool inf::operator != (const inf& r) const
+ {
+ return !operator==(r);
+ }
+
+ bool inf::operator < (const inf& r) const
+ {
+ // This could be implemented in terms of subtraction. However, it can be
+ // simplified since there is no need to calculate the accurate difference,
+ // just the direction of the difference. I compare from msB down and as
+ // soon as a byte difference is found, that defines the ordering. The
+ // problem is that in 2's-complement, all negative values are greater than
+ // all natural values if you just do a straight unsigned comparison. I
+ // handle this by doing a preliminary test for different signs.
+
+ // For example, a 3-bit signed type has the coding:
+ // 000 = 0
+ // ...
+ // 011 = 3
+ // 100 = -4
+ // ...
+ // 111 = -1
+
+ // So, for natural values, the ordering of the integer values is the
+ // ordering of the bit patterns. Similarly, for negative values, the
+ // ordering of the integer values is the ordering of the bit patterns
+ // However, the bit patterns for the negative values are *greater than*
+ // the natural values. This is a side-effect of the naffness of
+ // 2's-complement representation
+
+ // first handle the case of comparing two values with different signs
+ bool l_sign = negative();
+ bool r_sign = r.negative();
+ if (l_sign != r_sign)
+ {
+ // one argument must be negative and the other natural
+ // the left is less if it is the negative one
+ return l_sign;
+ }
+ // the arguments are the same sign
+ // so the ordering is a simple unsigned byte-by-byte comparison
+ // However, this is complicated by the possibility that the values could be different lengths
+ byte l_extend = l_sign ? byte(255) : byte (0);
+ byte r_extend = r_sign ? byte(255) : byte (0);
+ std::string::size_type bytes = maximum(m_data.size(),r.m_data.size());
+ for (std::string::size_type i = bytes; i--; )
+ {
+ byte l_byte = (i < m_data.size() ? byte(m_data[i]) : l_extend);
+ byte r_byte = (i < r.m_data.size() ? byte(r.m_data[i]) : r_extend);
+ if (l_byte != r_byte)
+ return l_byte < r_byte;
+ }
+ // if I get here, the two are equal, so that is not less-than
+ return false;
+ }
+
+ bool inf::operator <= (const inf& r) const
+ {
+ return !(r < *this);
+ }
+
+ bool inf::operator > (const inf& r) const
+ {
+ return r < *this;
+ }
+
+ bool inf::operator >= (const inf& r) const
+ {
+ return !(*this < r);
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ // logical operators
+
+ inf& inf::invert (void)
+ {
+ for (std::string::size_type i = 0; i < m_data.size(); i++)
+ m_data[i] = ~m_data[i];
+ return *this;
+ }
+
+ inf inf::operator ~ (void) const
+ {
+ inf result(*this);
+ result.invert();
+ return result;
+ }
+
+ inf& inf::operator &= (const inf& r)
+ {
+ // bitwise AND is extended to the length of the largest argument
+ byte l_extend = negative() ? byte(255) : byte (0);
+ byte r_extend = r.negative() ? byte(255) : byte (0);
+ std::string::size_type bytes = maximum(m_data.size(),r.m_data.size());
+ for (std::string::size_type i = 0; i < bytes; i++)
+ {
+ byte l_byte = (i < m_data.size() ? byte(m_data[i]) : l_extend);
+ byte r_byte = (i < r.m_data.size() ? byte(r.m_data[i]) : r_extend);
+ byte result = l_byte & r_byte;
+ if (i < m_data.size())
+ m_data[i] = result;
+ else
+ m_data.append(1,result);
+ }
+ // now reduce the result
+ reduce();
+ return *this;
+ }
+
+ inf inf::operator & (const inf& r) const
+ {
+ inf result(*this);
+ result &= r;
+ return result;
+ }
+
+ inf& inf::operator |= (const inf& r)
+ {
+ // bitwise OR is extended to the length of the largest argument
+ byte l_extend = negative() ? byte(255) : byte (0);
+ byte r_extend = r.negative() ? byte(255) : byte (0);
+ std::string::size_type bytes = maximum(m_data.size(),r.m_data.size());
+ for (std::string::size_type i = 0; i < bytes; i++)
+ {
+ byte l_byte = (i < m_data.size() ? byte(m_data[i]) : l_extend);
+ byte r_byte = (i < r.m_data.size() ? byte(r.m_data[i]) : r_extend);
+ byte result = l_byte | r_byte;
+ if (i < m_data.size())
+ m_data[i] = result;
+ else
+ m_data.append(1,result);
+ }
+ // now reduce the result
+ reduce();
+ return *this;
+ }
+
+ inf inf::operator | (const inf& r) const
+ {
+ inf result(*this);
+ result |= r;
+ return result;
+ }
+
+ inf& inf::operator ^= (const inf& r)
+ {
+ // bitwise XOR is extended to the length of the largest argument
+ byte l_extend = negative() ? byte(255) : byte (0);
+ byte r_extend = r.negative() ? byte(255) : byte (0);
+ std::string::size_type bytes = maximum(m_data.size(),r.m_data.size());
+ for (std::string::size_type i = 0; i < bytes; i++)
+ {
+ byte l_byte = (i < m_data.size() ? byte(m_data[i]) : l_extend);
+ byte r_byte = (i < r.m_data.size() ? byte(r.m_data[i]) : r_extend);
+ byte result = l_byte ^ r_byte;
+ if (i < m_data.size())
+ m_data[i] = result;
+ else
+ m_data.append(1,result);
+ }
+ // now reduce the result
+ reduce();
+ return *this;
+ }
+
+ inf inf::operator ^ (const inf& r) const
+ {
+ inf result(*this);
+ result ^= r;
+ return result;
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ // shift operators all preserve the value by increasing the word size
+
+ inf& inf::operator <<= (unsigned shift)
+ {
+ // left shift is a shift towards the msb, with 0s being shifted in at the lsb
+ // split this into a byte shift followed by a bit shift
+
+ // first expand the value to be big enough for the result
+ std::string::size_type new_size = (indexable_bits() + shift + 7) / 8;
+ byte extend = negative() ? byte(255) : byte (0);
+ while (m_data.size() < new_size)
+ m_data.append(1,extend);
+ // now do the byte shift
+ unsigned byte_shift = shift/8;
+ if (byte_shift > 0)
+ {
+ for (std::string::size_type b = new_size; b--; )
+ m_data[b] = (b >= byte_shift) ? m_data[b-byte_shift] : byte(0);
+ }
+ // and finally the bit shift
+ unsigned bit_shift = shift%8;
+ if (bit_shift > 0)
+ {
+ for (std::string::size_type b = new_size; b--; )
+ {
+ byte current = byte(m_data[b]);
+ byte previous = b > 0 ? m_data[b-1] : byte(0);
+ m_data[b] = (current << bit_shift) | (previous >> (8 - bit_shift));
+ }
+ }
+ // now reduce the result
+ reduce();
+ return *this;
+ }
+
+ inf inf::operator << (unsigned shift) const
+ {
+ inf result(*this);
+ result <<= shift;
+ return result;
+ }
+
+ inf& inf::operator >>= (unsigned shift)
+ {
+ // right shift is a shift towards the lsb, with sign bits being shifted in at the msb
+ // split this into a byte shift followed by a bit shift
+
+ // a byte of sign bits
+ byte extend = negative() ? byte(255) : byte (0);
+ // do the byte shift
+ unsigned byte_shift = shift/8;
+ if (byte_shift > 0)
+ {
+ for (std::string::size_type b = 0; b < m_data.size(); b++)
+ m_data[b] = (b + byte_shift < m_data.size()) ? m_data[b+byte_shift] : extend;
+ }
+ // and finally the bit shift
+ unsigned bit_shift = shift%8;
+ if (bit_shift > 0)
+ {
+ for (std::string::size_type b = 0; b < m_data.size(); b++)
+ {
+ byte current = byte(m_data[b]);
+ byte next = ((b+1) < m_data.size()) ? m_data[b+1] : extend;
+ byte shifted = (current >> bit_shift) | (next << (8 - bit_shift));
+ m_data[b] = shifted;
+ }
+ }
+ // now reduce the result
+ reduce();
+ return *this;
+ }
+
+ inf inf::operator >> (unsigned shift) const
+ {
+ inf result(*this);
+ result >>= shift;
+ return result;
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ // negation operators
+
+ inf& inf::negate (void)
+ {
+ // do 2's-complement negation
+ // equivalent to inversion plus one
+ invert();
+ operator += (inf(1));
+ return *this;
+ }
+
+ inf inf::operator - (void) const
+ {
+ inf result(*this);
+ result.negate();
+ return result;
+ }
+
+ inf& inf::abs(void)
+ {
+ if (negative()) negate();
+ return *this;
+ }
+
+ inf abs(const inf& i)
+ {
+ inf result = i;
+ result.abs();
+ return result;
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ // addition operators
+
+ inf& inf::operator += (const inf& r)
+ {
+ // do 2's-complement addition
+ // Note that the addition can give a result that is larger than either argument
+ byte carry = 0;
+ std::string::size_type max_size = maximum(m_data.size(),r.m_data.size());
+ byte l_extend = negative() ? byte(255) : byte (0);
+ byte r_extend = r.negative() ? byte(255) : byte (0);
+ for (std::string::size_type i = 0; i < max_size; i++)
+ {
+ byte l_byte = (i < m_data.size() ? byte(m_data[i]) : l_extend);
+ byte r_byte = (i < r.m_data.size() ? byte(r.m_data[i]) : r_extend);
+ // calculate the addition in a type that is bigger than a byte in order to catch the carry-out
+ unsigned short result = ((unsigned short)(l_byte)) + ((unsigned short)(r_byte)) + carry;
+ // now truncate the result to get the lsB
+ if (i < m_data.size())
+ m_data[i] = byte(result);
+ else
+ m_data.append(1,byte(result));
+ // and capture the carry out by grabbing the second byte of the result
+ carry = byte(result >> 8);
+ }
+ // if the result overflowed or underflowed, add an extra byte to catch it
+ unsigned short result = ((unsigned short)(l_extend)) + ((unsigned short)(r_extend)) + carry;
+ if (byte(result) != (negative() ? byte(255) : byte(0)))
+ m_data.append(1,byte(result));
+ // now reduce the result
+ reduce();
+ return *this;
+ }
+
+ inf inf::operator + (const inf& r) const
+ {
+ inf result(*this);
+ result += r;
+ return result;
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ // subtraction operators
+
+ inf& inf::operator -= (const inf& r)
+ {
+ // subtraction is defined in terms of negation and addition
+ inf negated = -r;
+ operator += (negated);
+ return *this;
+ }
+
+ inf inf::operator - (const inf& r) const
+ {
+ inf result(*this);
+ result -= r;
+ return result;
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ // multiplication operators
+
+ inf& inf::operator *= (const inf& r)
+ {
+ // 2's complement multiplication
+ // one day I'll do a more efficient version than this based on the underlying representation
+ inf left(*this);
+ inf right = r;
+ // make the right value natural but preserve its sign for later
+ bool right_negative = right.negative();
+ right.abs();
+ // implemented as a series of conditional additions
+ operator = (0);
+ // left.resize(right.bits() + left.bits() - 1);
+ left <<= right.bits()-1;
+ for (unsigned i = right.bits(); i--; )
+ {
+ if (right[i])
+ operator += (left);
+ left >>= 1;
+ }
+ if (right_negative)
+ negate();
+ // now reduce the result
+ reduce();
+ return *this;
+ }
+
+ inf inf::operator * (const inf& r) const
+ {
+ inf result(*this);
+ result *= r;
+ return result;
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ // division and remainder operators
+
+ std::pair<inf,inf> inf::divide(const inf& right) const throw(divide_by_zero)
+ {
+ if (right.zero())
+ throw divide_by_zero("stlplus::inf::divide");
+ inf numerator(*this);
+ inf denominator = right;
+ // make the numerator natural but preserve the sign for later
+ bool numerator_negative = numerator.negative();
+ numerator.abs();
+ // same with the denominator
+ bool denominator_negative = denominator.negative();
+ denominator.abs();
+ // the quotient and remainder will form the result
+ // start with the quotiont zero and the remainder equal to the whole of the
+ // numerator, then do trial subtraction from this
+ inf quotient;
+ inf remainder = numerator;
+ // there's nothing more to do if the numerator is smaller than the denominator
+ // but otherwise do the division
+ if (numerator.bits() >= denominator.bits())
+ {
+ // make the quotient big enough to take the result
+ quotient.resize(numerator.bits());
+ // start with the numerator shifted to the far left
+ unsigned shift = numerator.bits() - denominator.bits();
+ denominator <<= shift;
+ // do the division by repeated subtraction,
+ for (unsigned i = shift+1; i--; )
+ {
+ if (remainder >= denominator)
+ {
+ remainder -= denominator;
+ quotient.set(i);
+ }
+ denominator >>= 1;
+ }
+ }
+ // now adjust the signs
+ // x/(-y) == (-x)/y == -(x/y)
+ if (numerator_negative != denominator_negative)
+ quotient.negate();
+ quotient.reduce();
+ // x%(-y) == x%y and (-x)%y == -(x%y)
+ if (numerator_negative)
+ remainder.negate();
+ remainder.reduce();
+ return std::pair<inf,inf>(quotient,remainder);
+ }
+
+ inf& inf::operator /= (const inf& r) throw(divide_by_zero)
+ {
+ std::pair<inf,inf> result = divide(r);
+ operator=(result.first);
+ return *this;
+ }
+
+ inf inf::operator / (const inf& r) const throw(divide_by_zero)
+ {
+ std::pair<inf,inf> result = divide(r);
+ return result.first;
+ }
+
+ inf& inf::operator %= (const inf& r) throw(divide_by_zero)
+ {
+ std::pair<inf,inf> result = divide(r);
+ operator=(result.second);
+ return *this;
+ }
+
+ inf inf::operator % (const inf& r) const throw(divide_by_zero)
+ {
+ std::pair<inf,inf> result = divide(r);
+ return result.second;
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ // prefix (void) and postfix (int) operators
+
+ inf& inf::operator ++ (void)
+ {
+ operator += (inf(1));
+ return *this;
+ }
+
+ inf inf::operator ++ (int)
+ {
+ inf old(*this);
+ operator += (inf(1));
+ return old;
+ }
+
+ inf& inf::operator -- (void)
+ {
+ operator -= (inf(1));
+ return *this;
+ }
+
+ inf inf::operator -- (int)
+ {
+ inf old(*this);
+ operator -= (inf(1));
+ return old;
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ // string representation and I/O routines
+
+ std::string inf::to_string(unsigned radix) const
+ throw(std::invalid_argument)
+ {
+ std::string result;
+ convert_to_string(*this, result, radix);
+ return result;
+ }
+
+ inf& inf::from_string(const std::string& value, unsigned radix)
+ throw(std::invalid_argument)
+ {
+ convert_from_string(value, *this, radix);
+ return *this;
+ }
+
+ std::ostream& operator << (std::ostream& str, const inf& i)
+ {
+ try
+ {
+ // get radix
+ unsigned radix = 10;
+ if (str.flags() & std::ios_base::oct)
+ radix = 8;
+ if (str.flags() & std::ios_base::hex)
+ radix = 16;
+ // the field width is handled by iostream, so I don't need to handle it as well
+ // generate the string representation then print it
+ str << i.to_string(radix);
+ }
+ catch(const std::invalid_argument)
+ {
+ str.setstate(std::ios_base::badbit);
+ }
+ return str;
+ }
+
+ std::istream& operator >> (std::istream& str, inf& i)
+ {
+ try
+ {
+ // get radix
+ unsigned radix = 10;
+ if (str.flags() & std::ios_base::oct)
+ radix = 8;
+ if (str.flags() & std::ios_base::hex)
+ radix = 16;
+ // now get the string image of the value
+ std::string image;
+ str >> image;
+ // and convert to inf
+ i.from_string(image, radix);
+ }
+ catch(const std::invalid_argument)
+ {
+ str.setstate(std::ios_base::badbit);
+ }
+ return str;
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ // diagnostic dump
+ // just convert to hex
+
+ std::string inf::image_debug(void) const
+ {
+ // create this dump in the human-readable form, i.e. msB to the left
+ std::string result = "0x";
+ for (std::string::size_type i = m_data.size(); i--; )
+ {
+ byte current = m_data[i];
+ byte msB = (current & byte(0xf0)) >> 4;
+ result += to_char[msB];
+ byte lsB = (current & byte(0x0f));
+ result += to_char[lsB];
+ }
+ return result;
+ }
+
+ const std::string& inf::get_bytes(void) const
+ {
+ return m_data;
+ }
+
+ void inf::set_bytes(const std::string& data)
+ {
+ m_data = data;
+ }
+
+} // end namespace stlplus
diff --git a/src/tool/moneycount/inf.hpp b/src/tool/moneycount/inf.hpp new file mode 100644 index 0000000..f28541a --- /dev/null +++ b/src/tool/moneycount/inf.hpp @@ -0,0 +1,228 @@ +#ifndef STLPLUS_INF
+#define STLPLUS_INF
+////////////////////////////////////////////////////////////////////////////////
+
+// Author: Andy Rushton
+// Copyright: (c) Southampton University 1999-2004
+// (c) Andy Rushton 2004-2009
+// License: BSD License, see ../docs/license.html
+
+// An infinite-precision integer class. This allows calculations on large
+// integers to be performed without overflow.
+
+// this class can throw the following exceptions:
+// std::out_of_range
+// std::overflow_error
+// std::invalid_argument
+// stlplus::divide_by_zero // why doesn't std have this?
+// all of these are derivations of the baseclass:
+// std::logic_error
+// So you can catch all of them by catching the baseclass
+
+// Warning: inf was never intended to be fast, it is just for programs which
+// need a bit of infinite-precision integer arithmetic. For high-performance
+// processing, use the Gnu Multi-Precision (GMP) library. The inf type is just
+// easier to integrate and is already ported to all platforms and compilers
+// that STLplus is ported to.
+
+////////////////////////////////////////////////////////////////////////////////
+#include "portability_fixes.hpp"
+#include "portability_exceptions.hpp"
+#include <string>
+#include <iostream>
+
+////////////////////////////////////////////////////////////////////////////////
+
+namespace stlplus
+{
+
+////////////////////////////////////////////////////////////////////////////////
+
+ class inf
+ {
+ public:
+
+ //////////////////////////////////////////////////////////////////////////////
+ // constructors and assignments initialise the inf
+
+ // the void constructor initialises to zero, the others initialise to the
+ // value of the C integer type or the text value contained in the string
+
+ inf(void);
+ explicit inf(short);
+ explicit inf(unsigned short);
+ explicit inf(int);
+ explicit inf(unsigned);
+ explicit inf(long);
+ explicit inf(unsigned long);
+ explicit inf(const std::string&) throw(std::invalid_argument);
+ inf(const inf&);
+
+ ~inf(void);
+
+ // assignments with equivalent behaviour to the constructors
+
+ inf& operator = (short);
+ inf& operator = (unsigned short);
+ inf& operator = (int);
+ inf& operator = (unsigned);
+ inf& operator = (long);
+ inf& operator = (unsigned long);
+ inf& operator = (const std::string&) throw(std::invalid_argument);
+ inf& operator = (const inf&);
+
+ //////////////////////////////////////////////////////////////////////////////
+ // conversions back to the C types
+ // truncate: controls the behaviour when the value is too long for the result
+ // true: truncate the value
+ // false: throw an exception
+
+ short to_short(bool truncate = true) const throw(std::overflow_error);
+ unsigned short to_unsigned_short(bool truncate = true) const throw(std::overflow_error);
+
+ int to_int(bool truncate = true) const throw(std::overflow_error);
+ unsigned to_unsigned(bool truncate = true) const throw(std::overflow_error);
+
+ long to_long(bool truncate = true) const throw(std::overflow_error);
+ unsigned long to_unsigned_long(bool truncate = true) const throw(std::overflow_error);
+
+ //////////////////////////////////////////////////////////////////////////////
+ // bitwise manipulation
+
+ void resize(unsigned bits);
+ void reduce(void);
+
+ // the number of significant bits in the value
+ unsigned bits (void) const;
+ unsigned size (void) const;
+
+ // the number of bits that can be accessed by the bit() method (=bits() rounded up to the next byte)
+ unsigned indexable_bits(void) const;
+
+ bool bit (unsigned index) const throw(std::out_of_range);
+ bool operator [] (unsigned index) const throw(std::out_of_range);
+
+ void set (unsigned index) throw(std::out_of_range);
+ void clear (unsigned index) throw(std::out_of_range);
+ void preset (unsigned index, bool value) throw(std::out_of_range);
+
+ inf slice(unsigned low, unsigned high) const throw(std::out_of_range);
+
+ //////////////////////////////////////////////////////////////////////////////
+ // tests for common values or ranges
+
+ bool negative (void) const;
+ bool natural (void) const;
+ bool positive (void) const;
+ bool zero (void) const;
+ bool non_zero (void) const;
+
+ // tests used in if(i) and if(!i)
+// operator bool (void) const;
+ bool operator ! (void) const;
+
+ //////////////////////////////////////////////////////////////////////////////
+ // comparisons
+
+ bool operator == (const inf&) const;
+ bool operator != (const inf&) const;
+ bool operator < (const inf&) const;
+ bool operator <= (const inf&) const;
+ bool operator > (const inf&) const;
+ bool operator >= (const inf&) const;
+
+ //////////////////////////////////////////////////////////////////////////////
+ // bitwise logic operations
+
+ inf& invert (void);
+ inf operator ~ (void) const;
+
+ inf& operator &= (const inf&);
+ inf operator & (const inf&) const;
+
+ inf& operator |= (const inf&);
+ inf operator | (const inf&) const;
+
+ inf& operator ^= (const inf&);
+ inf operator ^ (const inf&) const;
+
+ inf& operator <<= (unsigned shift);
+ inf operator << (unsigned shift) const;
+
+ inf& operator >>= (unsigned shift);
+ inf operator >> (unsigned shift) const;
+
+ //////////////////////////////////////////////////////////////////////////////
+ // arithmetic operations
+
+ inf& negate (void);
+ inf operator - (void) const;
+
+ inf& abs(void);
+ friend inf abs(const inf&);
+
+ inf& operator += (const inf&);
+ inf operator + (const inf&) const;
+
+ inf& operator -= (const inf&);
+ inf operator - (const inf&) const;
+
+ inf& operator *= (const inf&);
+ inf operator * (const inf&) const;
+
+ inf& operator /= (const inf&) throw(divide_by_zero);
+ inf operator / (const inf&) const throw(divide_by_zero);
+
+ inf& operator %= (const inf&) throw(divide_by_zero);
+ inf operator % (const inf&) const throw(divide_by_zero);
+
+ // combined division operator - returns the result pair(quotient,remainder) in one go
+ std::pair<inf,inf> divide(const inf&) const throw(divide_by_zero);
+
+ //////////////////////////////////////////////////////////////////////////////
+ // pre- and post- increment and decrement
+
+ inf& operator ++ (void);
+ inf operator ++ (int);
+ inf& operator -- (void);
+ inf operator -- (int);
+
+ //////////////////////////////////////////////////////////////////////////////
+ // string representation and I/O
+
+ std::string image_debug(void) const;
+
+ // conversion to a string representation
+ // radix must be 10, 2, 8 or 16
+ std::string to_string(unsigned radix = 10) const
+ throw(std::invalid_argument);
+
+ // conversion from a string
+ // radix == 0 - radix is deduced from the input - assumed 10 unless number is prefixed by 0b, 0 or 0x
+ // however, you can specify the radix to be 10, 2, 8 or 16 to force that interpretation
+ inf& from_string(const std::string&, unsigned radix = 0)
+ throw(std::invalid_argument);
+
+ //////////////////////////////////////////////////////////////////////////////
+ private:
+ std::string m_data;
+ public:
+ const std::string& get_bytes(void) const;
+ void set_bytes(const std::string&);
+ };
+
+ ////////////////////////////////////////////////////////////////////////////////
+ // redefine friends for gcc v4.1
+
+ inf abs(const inf&);
+
+ ////////////////////////////////////////////////////////////////////////////////
+
+ std::ostream& operator << (std::ostream&, const inf&);
+ std::istream& operator >> (std::istream&, inf&);
+
+ ////////////////////////////////////////////////////////////////////////////////
+
+} // end namespace stlplus
+
+#endif
diff --git a/src/tool/moneycount/main.cpp b/src/tool/moneycount/main.cpp index 0e090bd..d15f223 100644 --- a/src/tool/moneycount/main.cpp +++ b/src/tool/moneycount/main.cpp @@ -9,6 +9,7 @@ #include "mmo.h" #include "athena_text.h" +#include "inf.hpp" #define ATHENA_FILE "save/athena.txt" #define ACCREG_FILE "save/accreg.txt" @@ -79,13 +80,26 @@ void countAccReg() fp.close(); } -long long stdDevTotal = 0; -long long sum = 0; -int mean = 0; +stlplus::inf stdDevTotal(0); +stlplus::inf sum(0); +stlplus::inf mean(0); bool lessthan (int i,int j) { return (i<j); } -void findstddev(int i) { stdDevTotal += (i - mean) * (i - mean); } -void findSum(int i) { sum += i; } +void findstddev(int i) { stdDevTotal += stlplus::inf((stlplus::inf(i) - mean) * (stlplus::inf(i) - mean)); } +void findSum(int i) { sum += stlplus::inf(i); } + +stlplus::inf infsqrt(stlplus::inf &x) +{ + stlplus::inf old(x); + stlplus::inf newv(x / stlplus::inf(2)); + while (old - newv > stlplus::inf(1)) + { + old = newv; + newv = old - (old * old - x) / (stlplus::inf(2) * old); + } + return newv; +} + void showStats() { @@ -97,14 +111,14 @@ void showStats() std::sort(values.begin(), values.end(), lessthan); std::for_each(values.begin(), values.end(), findSum); - long long total = sum; - int count = values.size(); - mean = total / count; + stlplus::inf total(sum); + stlplus::inf count(values.size()); + stlplus::inf mean(total / count); std::for_each(values.begin(), values.end(), findstddev); - int a4th = count / 4; - int a10th = count / 10; + int a4th = stlplus::inf(count / stlplus::inf(4)).to_int(); + int a10th = stlplus::inf(count / stlplus::inf(10)).to_int(); int lower = values[0], @@ -126,13 +140,15 @@ void showStats() t8 = values[a10th * 8], t9 = values[a10th * 9], - upper = values[count - 1]; + upper = values[count.to_int() - 1]; + + stlplus::inf variance(stdDevTotal / count); std::cout << "Sum = " << total << "\nCount = " << count << "\nMean = " << mean - << "\nSimple Variance = " << (stdDevTotal / (count - 1)) - << "\nStandard Deviation = " << std::sqrt(stdDevTotal / (count - 1)) + << "\nSimple Variance = " << variance + << "\nStandard Deviation = " << infsqrt(variance) << "\nLower bound = " << lower << "\n10th Percentile = " << t1 << "\n20th Percentile = " << t2 diff --git a/src/tool/moneycount/portability_exceptions.hpp b/src/tool/moneycount/portability_exceptions.hpp new file mode 100644 index 0000000..c66b7bf --- /dev/null +++ b/src/tool/moneycount/portability_exceptions.hpp @@ -0,0 +1,33 @@ +#ifndef STLPLUS_PORTABILITY_EXCEPTIONS
+#define STLPLUS_PORTABILITY_EXCEPTIONS
+////////////////////////////////////////////////////////////////////////////////
+
+// Author: Andy Rushton
+// Copyright: (c) Southampton University 1999-2004
+// (c) Andy Rushton 2004-2009
+// License: BSD License, see ../docs/license.html
+
+// Adds missing arithmetic exceptions used in this library but missing from std
+
+////////////////////////////////////////////////////////////////////////////////
+#include "portability_fixes.hpp"
+#include <string>
+#include <stdexcept>
+
+namespace stlplus
+{
+
+ ////////////////////////////////////////////////////////////////////////////////
+ // thrown by division when the divisor is zero
+ // This is a subclass of std::logic_error so can be caught by a generic catch clause for the superclass
+
+ class divide_by_zero : public std::logic_error {
+ public:
+ divide_by_zero (const std::string& what_arg): std::logic_error (what_arg) { }
+ };
+
+////////////////////////////////////////////////////////////////////////////////
+
+} // end namespace stlplus
+
+#endif
diff --git a/src/tool/moneycount/portability_fixes.cpp b/src/tool/moneycount/portability_fixes.cpp new file mode 100644 index 0000000..e26ee28 --- /dev/null +++ b/src/tool/moneycount/portability_fixes.cpp @@ -0,0 +1,39 @@ +////////////////////////////////////////////////////////////////////////////////
+
+// Author: Andy Rushton
+// Copyright: (c) Southampton University 1999-2004
+// (c) Andy Rushton 2004-2009
+// License: BSD License, see ../docs/license.html
+
+////////////////////////////////////////////////////////////////////////////////
+#include "portability_fixes.hpp"
+
+#ifdef MSWINDOWS
+#include "windows.h"
+#endif
+
+////////////////////////////////////////////////////////////////////////////////
+// problems with missing functions
+////////////////////////////////////////////////////////////////////////////////
+
+#ifdef MSWINDOWS
+unsigned sleep(unsigned seconds)
+{
+ Sleep(1000*seconds);
+ // should return remaining time if interrupted - however Windoze Sleep cannot be interrupted
+ return 0;
+}
+#endif
+
+////////////////////////////////////////////////////////////////////////////////
+// Function for establishing endian-ness
+////////////////////////////////////////////////////////////////////////////////
+
+bool stlplus::little_endian(void)
+{
+ int sample = 1;
+ char* sample_bytes = (char*)&sample;
+ return sample_bytes[0] != 0;
+}
+
+////////////////////////////////////////////////////////////////////////////////
diff --git a/src/tool/moneycount/portability_fixes.hpp b/src/tool/moneycount/portability_fixes.hpp new file mode 100644 index 0000000..b6a030c --- /dev/null +++ b/src/tool/moneycount/portability_fixes.hpp @@ -0,0 +1,127 @@ +#ifndef STLPLUS_PORTABILITY_FIXES
+#define STLPLUS_PORTABILITY_FIXES
+////////////////////////////////////////////////////////////////////////////////
+
+// Author: Andy Rushton
+// Copyright: (c) Southampton University 1999-2004
+// (c) Andy Rushton 2004-2009
+// License: BSD License, see ../docs/license.html
+
+// Contains work arounds for OS or Compiler specific problems to try to make
+// them look more alike
+
+// It is strongly recommended that this header be included as the first
+// #include in every source file
+
+////////////////////////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////////////////////////
+// Problem with MicroSoft defining two different macros to identify Windows
+////////////////////////////////////////////////////////////////////////////////
+
+#if defined(_WIN32) || defined(_WIN32_WCE)
+#define MSWINDOWS
+#endif
+
+////////////////////////////////////////////////////////////////////////////////
+// Problems with unnecessary or unfixable compiler warnings
+////////////////////////////////////////////////////////////////////////////////
+
+#ifdef _MSC_VER
+// Microsoft Visual Studio
+// shut up the following irritating warnings
+// 4786 - VC6, identifier string exceeded maximum allowable length and was truncated (only affects debugger)
+// 4305 - VC6, identifier type was converted to a smaller type
+// 4503 - VC6, decorated name was longer than the maximum the compiler allows (only affects debugger)
+// 4309 - VC6, type conversion operation caused a constant to exceeded the space allocated for it
+// 4290 - VC6, C++ exception specification ignored
+// 4800 - VC6, forcing value to bool 'true' or 'false' (performance warning)
+// 4675 - VC7.1, "change" in function overload resolution _might_ have altered program
+// 4996 - VC8, 'xxxx' was declared deprecated
+#pragma warning(disable: 4786 4305 4503 4309 4290 4800 4675 4996)
+#endif
+
+#ifdef __BORLANDC__
+// Borland
+// Shut up the following irritating warnings
+// 8026 - Functions with exception specifications are not expanded inline
+// 8027 - Functions with xxx are not expanded inline
+#pragma warn -8026
+#pragma warn -8027
+#endif
+
+////////////////////////////////////////////////////////////////////////////////
+// Problems with redefinition of min/max in various different versions of library headers
+////////////////////////////////////////////////////////////////////////////////
+
+// The Windows headers define macros called max/min which conflict with the templates std::max and std::min.
+// So, to avoid conflicts, MS removed the std::max/min rather than fixing the problem!
+// From Visual Studio .NET (SV7, compiler version 13.00) the STL templates have been added correctly.
+// For MFC compatibility, only undef min and max in non-MFC programs - some bits of MFC
+// use macro min/max in headers.
+
+// I've created extra template function definitions minimum/maximum that avoid all the problems above
+
+namespace stlplus
+{
+ template<typename T> const T& maximum(const T& l, const T& r) {return l > r ? l : r;}
+ template<typename T> const T& minimum(const T& l, const T& r) {return l < r ? l : r;}
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Problems with differences between namespaces
+////////////////////////////////////////////////////////////////////////////////
+
+// Note: not sure of the relevance of this - maybe deprecated?
+// problem in gcc pre-v3 where the sub-namespaces in std aren't present
+// this mean that the statement "using namespace std::rel_ops" created an error because the namespace didn't exist
+
+// I've done a fix here that creates an empty namespace for this case, but I
+// do *not* try to move the contents of std::rel_ops into namespace std
+// This fix only works if you use "using namespace std::rel_ops" to bring in the template relational operators (e.g. != defined i.t.o. ==)
+
+#ifdef __GNUC__
+namespace std
+{
+ namespace rel_ops
+ {
+ }
+}
+#endif
+
+////////////////////////////////////////////////////////////////////////////////
+// problems with missing functions
+////////////////////////////////////////////////////////////////////////////////
+
+#ifdef MSWINDOWS
+unsigned sleep(unsigned seconds);
+#else
+#include <unistd.h>
+#endif
+
+////////////////////////////////////////////////////////////////////////////////
+// Function for establishing endian-ness
+////////////////////////////////////////////////////////////////////////////////
+// Different machine architectures store data using different byte orders.
+// This is referred to as Big- and Little-Endian Byte Ordering.
+//
+// The issue is: where does a pointer to an integer type actually point?
+//
+// In both conventions, the address points to the left of the word but:
+// Big-Endian - The most significant byte is on the left end of a word
+// Little-Endian - The least significant byte is on the left end of a word
+//
+// Bytes are addressed left to right, so in big-endian order byte 0 is the
+// msB, whereas in little-endian order byte 0 is the lsB. For example,
+// Intel-based machines store data in little-endian byte order so byte 0 is
+// the lsB.
+//
+// This function establishes byte order at run-time
+
+namespace stlplus
+{
+ bool little_endian(void);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+#endif
|