/* * This file is a part of TTMath Bignum Library * and is distributed under the 3-Clause BSD Licence. * Author: Tomasz Sowa */ /* * Copyright (c) 2012, Tomasz Sowa * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * * Neither the name Tomasz Sowa nor the names of contributors to this * project may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef headerfilettmathdec #define headerfilettmathdec #include "ttmathtypes.h" #include "ttmaththreads.h" #include "ttmathuint.h" namespace ttmath { template class Dec { public: UInt value; unsigned char info; /*! Sign the mask of a bit from 'info' which means that there is a sign (when the bit is set) */ #define TTMATH_DEC_SIGN 128 /*! Not a number if this bit is set that there is not a valid number */ #define TTMATH_DEC_NAN 64 Dec() { info = TTMATH_DEC_NAN; } Dec(const char * s) { info = TTMATH_DEC_NAN; FromString(s); } Dec & operator=(const char * s) { FromString(s); return *this; } uint FromString(const char * s, const char ** after_source = 0, bool * value_read = 0) { return FromStringBase(s, after_source, value_read); } void ToString(std::string & result) const { ToStringBase(result); } /*! this method clears a specific bit in the 'info' variable bit is one of: */ void ClearInfoBit(unsigned char bit) { info = info & (~bit); } /*! this method sets a specific bit in the 'info' variable bit is one of: */ void SetInfoBit(unsigned char bit) { info = info | bit; } /*! this method returns true if a specific bit in the 'info' variable is set bit is one of: */ bool IsInfoBit(unsigned char bit) const { return (info & bit) != 0; } bool IsNan() const { return IsInfoBit(TTMATH_DEC_NAN); } bool IsSign() const { return IsInfoBit(TTMATH_DEC_SIGN); } /*! this method sets the sign e.g. -1 -> -1 2 -> -2 we do not check whether there is a zero or not, if you're using this method you must be sure that the value is (or will be afterwards) different from zero */ void SetSign() { SetInfoBit(TTMATH_DEC_SIGN); } void SetNaN() { SetInfoBit(TTMATH_DEC_NAN); } void Abs() { ClearInfoBit(TTMATH_DEC_SIGN); } uint Add(const Dec & arg) { uint c = 0; if( IsSign() == arg.IsSign() ) { c += value.Add(arg.value); } else { bool is_sign; if( value > arg.value ) { is_sign = IsSign(); value.Sub(arg.value); } else { is_sign = arg.IsSign(); UInt temp(this->value); value = arg.value; value.Sub(temp); } is_sign ? SetSign() : Abs(); } if( c ) SetNaN(); return (c==0)? 0 : 1; } /* uint Sub(const Dec & arg) { } */ private: #ifndef TTMATH_MULTITHREADS /*! */ void SetMultipler(UInt & result) { // this guardian is initialized before the program runs (static POD type) static int guardian = 0; static UInt multipler; if( guardian == 0 ) { multipler = 10; multipler.Pow(dec_digits); guardian = 1; } result = multipler; } #else /*! */ void SetMultipler(UInt & result) { // this guardian is initialized before the program runs (static POD type) volatile static sig_atomic_t guardian = 0; static UInt * pmultipler; // double-checked locking if( guardian == 0 ) { ThreadLock thread_lock; // locking if( thread_lock.Lock() ) { static UInt multipler; if( guardian == 0 ) { pmultipler = &multipler; multipler = 10; multipler.Pow(dec_digits); guardian = 1; } } else { // there was a problem with locking, we store the result directly in 'result' object result = 10; result.Pow(dec_digits); return; } // automatically unlocking } result = *pmultipler; } #endif /*! an auxiliary method for converting from a string */ template uint FromStringBase(const char_type * s, const char_type ** after_source = 0, bool * value_read = 0) { UInt multipler; const char_type * after; uint c = 0; info = 0; Misc::SkipWhiteCharacters(s); if( *s == '-' ) { s += 1; SetSign(); } else if( *s == '+' ) { s += 1; } c += value.FromString(s, 10, &after, value_read); if( after_source ) *after_source = after; SetMultipler(multipler); c += value.Mul(multipler); if( *after == '.' ) c += FromStringBaseAfterComma(after+1, after_source); if( c ) SetInfoBit(TTMATH_DEC_NAN); return (c==0)? 0 : 1; } template uint FromStringBaseAfterComma(const char_type * s, const char_type ** after_source = 0, bool * value_read = 0) { UInt temp; UInt multipler; sint z; uint c = 0; size_t i = dec_digits; SetMultipler(multipler); for( ; i>0 && (z=Misc::CharToDigit(*s, 10)) != -1 ; --i, ++s ) { multipler.DivInt(10); temp.SetZero(); if( value_read ) *value_read = true; if( c == 0 ) { temp.table[0] = z; c += temp.Mul(multipler); c += value.Add(temp); } } if( i == 0 && (z=Misc::CharToDigit(*s, 10)) != -1 && z >= 5 ) c += value.AddOne(); if( after_source ) { while( (z=Misc::CharToDigit(*s, 10)) != -1 ) s += 1; *after_source = s; } return c; } template void ToStringBase(string_type & result) const { if( IsNan() ) { result = "NaN"; return; } value.ToStringBase(result, 10, IsSign()); if( dec_digits > 0 ) { size_t size = result.size(); if( IsSign() && size > 0 ) size -= 1; if( dec_digits >= size ) { size_t zeroes = dec_digits - size + 1; size_t start = IsSign() ? 1 : 0; result.insert(start, zeroes, '0'); } result.insert(result.end() - dec_digits, '.'); } } }; } // namespace #endif