added: struct: Conv
consists of some parameters used in ToString() and FromString() added: Big::ToString() can group digits e.g. 1234567 -> 1`234`567 added: Parser::SetGroup(int g) Parser::SetComma(int c, int c2 = 0) Parser::SetParamSep(int s) added: uint Big::ToString(std::string & result, const Conv & conv) uint Big::ToString(std::wstring & result, const Conv & conv) std::string Big::ToString(const Conv & conv) const std::string Big::ToString() added: uint FromString(const char * source, const Conv & conv, const char **, bool *) uint FromString(const wchar_t * source, const Conv & conv, const wchar_t **, bool *) uint FromString(const std::string & string, const Conv & conv, const wchar_t **, bool *) uint FromString(const std::wstring & string, const Conv & conv, const wchar_t **, bool *) removed: macros: TTMATH_COMMA_CHARACTER_1 and TTMATH_COMMA_CHARACTER_2 the comma characters we have in Conv struct now git-svn-id: svn://ttmath.org/publicrep/ttmath/trunk@226 e52654a7-88a9-db11-a3e9-0013d4bc506e
This commit is contained in:
parent
413c83de45
commit
2feabc64e2
22
CHANGELOG
22
CHANGELOG
|
@ -1,4 +1,4 @@
|
||||||
Version 0.9.0 prerelease (2009.10.25):
|
Version 0.9.0 prerelease (2009.11.01):
|
||||||
* added: support for wide characters (wchar_t, std::wstring)
|
* added: support for wide characters (wchar_t, std::wstring)
|
||||||
* added: Big::IsInteger()
|
* added: Big::IsInteger()
|
||||||
returns true if the value is integer (without fraction)
|
returns true if the value is integer (without fraction)
|
||||||
|
@ -28,6 +28,22 @@ Version 0.9.0 prerelease (2009.10.25):
|
||||||
(at least one mathematical operator was used or a function or variable)
|
(at least one mathematical operator was used or a function or variable)
|
||||||
* added: to the parser: operator percentage
|
* added: to the parser: operator percentage
|
||||||
e.g. 1000-50%=1000-(1000*0,5)=500
|
e.g. 1000-50%=1000-(1000*0,5)=500
|
||||||
|
* added: struct: Conv
|
||||||
|
consists of some parameters used
|
||||||
|
in ToString() and FromString()
|
||||||
|
* added: Big::ToString() can group digits
|
||||||
|
e.g. 1234567 -> 1`234`567
|
||||||
|
* added: Parser::SetGroup(int g)
|
||||||
|
Parser::SetComma(int c, int c2 = 0)
|
||||||
|
Parser::SetParamSep(int s)
|
||||||
|
* added: uint Big::ToString(std::string & result, const Conv & conv)
|
||||||
|
uint Big::ToString(std::wstring & result, const Conv & conv)
|
||||||
|
std::string Big::ToString(const Conv & conv) const
|
||||||
|
std::string Big::ToString()
|
||||||
|
* added: uint FromString(const char * source, const Conv & conv, const char **, bool *)
|
||||||
|
uint FromString(const wchar_t * source, const Conv & conv, const wchar_t **, bool *)
|
||||||
|
uint FromString(const std::string & string, const Conv & conv, const wchar_t **, bool *)
|
||||||
|
uint FromString(const std::wstring & string, const Conv & conv, const wchar_t **, bool *)
|
||||||
* changed: Factorial() is using the Gamma() function now
|
* changed: Factorial() is using the Gamma() function now
|
||||||
* changed: Big::Div(ss2)
|
* changed: Big::Div(ss2)
|
||||||
Big::Mod(ss2)
|
Big::Mod(ss2)
|
||||||
|
@ -36,7 +52,9 @@ Version 0.9.0 prerelease (2009.10.25):
|
||||||
* removed: Parser<>::SetFactorialMax() method
|
* removed: Parser<>::SetFactorialMax() method
|
||||||
the factorial() is such a fast now that we don't need the method longer
|
the factorial() is such a fast now that we don't need the method longer
|
||||||
* removed: ErrorCode::err_too_big_factorial
|
* removed: ErrorCode::err_too_big_factorial
|
||||||
|
* removed: macros: TTMATH_COMMA_CHARACTER_1 and TTMATH_COMMA_CHARACTER_2
|
||||||
|
the comma characters we have in Conv struct now
|
||||||
|
|
||||||
|
|
||||||
Version 0.8.6 (2009.10.25):
|
Version 0.8.6 (2009.10.25):
|
||||||
* fixed: UInt::SetBitInWord(uint & value, uint bit) set 1 if the bit was
|
* fixed: UInt::SetBitInWord(uint & value, uint bit) set 1 if the bit was
|
||||||
|
|
|
@ -2809,82 +2809,114 @@ public:
|
||||||
|
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
a method for converting the value into a string with a base equal 'base'
|
a method for converting into a string
|
||||||
|
struct Conv is defined in ttmathtypes.h, look there for more information about parameters
|
||||||
input:
|
|
||||||
* base - a base (radix) on which the value will be shown
|
|
||||||
|
|
||||||
* if 'always_scientific' is true the result will be shown in 'scientific' mode
|
|
||||||
if 'always_scientific' is false the result will be shown
|
|
||||||
either as 'scientific' or 'normal' mode, it depends whether the abs(exponent)
|
|
||||||
is greater than 'when_scientific' or not, if it's greater the value
|
|
||||||
will be printed as 'scientific'
|
|
||||||
|
|
||||||
* 'max_digit_after_comma' - rounding
|
|
||||||
if 'max_digit_after_comma' is equal -1 that all digits in the mantissa
|
|
||||||
will be printed
|
|
||||||
if 'max_digit_after_comma' is equal or greater than zero
|
|
||||||
that only 'max_digit_after_comma' after the comma operator will be shown
|
|
||||||
(if 'max_digit_after_comma' is equal zero there'll be shown only
|
|
||||||
integer value without the comma)
|
|
||||||
for example when the value is:
|
|
||||||
12.345678 and max_digit_after_comma is 4
|
|
||||||
then the result will be
|
|
||||||
12.3457 (the last digit was rounded)
|
|
||||||
if there isn't the comma operator (when the value is too big and we're printing
|
|
||||||
it not as scientific) 'max_digit_after_comma' will be ignored
|
|
||||||
|
|
||||||
* if 'remove_trailing_zeroes' is true that not mattered digits
|
|
||||||
in the mantissa will be cut off
|
|
||||||
(zero characters at the end -- after the comma operator)
|
|
||||||
|
|
||||||
* decimal_point - a character which will be used as a decimal point
|
|
||||||
|
|
||||||
output:
|
output:
|
||||||
return value:
|
return value:
|
||||||
0 - ok and 'result' will be an object of type std::string (or std::wstring) which holds the value
|
0 - ok and 'result' will be an object of type std::string (or std::wstring) which holds the value
|
||||||
1 - if there was a carry (shoudn't be in a normal situation - if is that means there
|
1 - if there is a carry (it shoudn't be in a normal situation - if it is that means there
|
||||||
is somewhere an error in the library)
|
is somewhere an error in the library)
|
||||||
*/
|
*/
|
||||||
uint ToString( std::string & result,
|
uint ToString( std::string & result,
|
||||||
uint base = 10,
|
uint base = 10,
|
||||||
bool always_scientific = false,
|
bool scient = false,
|
||||||
sint when_scientific = 15,
|
sint scient_from = 15,
|
||||||
sint max_digit_after_comma = -1,
|
sint comma_digits = -1,
|
||||||
bool remove_trailing_zeroes = true,
|
bool trim_zeroes = true,
|
||||||
char decimal_point = TTMATH_COMMA_CHARACTER_1 ) const
|
wchar_t comma = '.' ) const
|
||||||
{
|
{
|
||||||
return ToStringBase(result, base, always_scientific, when_scientific,
|
Conv conv;
|
||||||
max_digit_after_comma, remove_trailing_zeroes, decimal_point);
|
|
||||||
|
conv.base = base;
|
||||||
|
conv.scient = scient;
|
||||||
|
conv.scient_from = scient_from;
|
||||||
|
conv.comma_digits = comma_digits;
|
||||||
|
conv.trim_zeroes = trim_zeroes;
|
||||||
|
conv.comma = static_cast<uint>(comma);
|
||||||
|
|
||||||
|
return ToStringBase<std::string, char>(result, conv);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
a method for converting the value into a string with a base equal 'base'
|
a method for converting into a string
|
||||||
|
struct Conv is defined in ttmathtypes.h, look there for more information about parameters
|
||||||
*/
|
*/
|
||||||
uint ToString( std::wstring & result,
|
uint ToString( std::wstring & result,
|
||||||
uint base = 10,
|
uint base = 10,
|
||||||
bool always_scientific = false,
|
bool scient = false,
|
||||||
sint when_scientific = 15,
|
sint scient_from = 15,
|
||||||
sint max_digit_after_comma = -1,
|
sint comma_digits = -1,
|
||||||
bool remove_trailing_zeroes = true,
|
bool trim_zeroes = true,
|
||||||
wchar_t decimal_point = TTMATH_COMMA_CHARACTER_1 ) const
|
wchar_t comma = '.' ) const
|
||||||
{
|
{
|
||||||
return ToStringBase(result, base, always_scientific, when_scientific,
|
Conv conv;
|
||||||
max_digit_after_comma, remove_trailing_zeroes, decimal_point);
|
|
||||||
|
conv.base = base;
|
||||||
|
conv.scient = scient;
|
||||||
|
conv.scient_from = scient_from;
|
||||||
|
conv.comma_digits = comma_digits;
|
||||||
|
conv.trim_zeroes = trim_zeroes;
|
||||||
|
conv.comma = static_cast<uint>(comma);
|
||||||
|
|
||||||
|
return ToStringBase<std::wstring, wchar_t>(result, conv);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*!
|
||||||
|
a method for converting into a string
|
||||||
|
struct Conv is defined in ttmathtypes.h, look there for more information about parameters
|
||||||
|
*/
|
||||||
|
uint ToString(std::string & result, const Conv & conv) const
|
||||||
|
{
|
||||||
|
return ToStringBase<std::string, char>(result, conv);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*!
|
||||||
|
a method for converting into a string
|
||||||
|
struct Conv is defined in ttmathtypes.h, look there for more information about parameters
|
||||||
|
*/
|
||||||
|
uint ToString(std::wstring & result, const Conv & conv) const
|
||||||
|
{
|
||||||
|
return ToStringBase<std::wstring, wchar_t>(result, conv);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*!
|
||||||
|
a method for converting into a string
|
||||||
|
struct Conv is defined in ttmathtypes.h, look there for more information about parameters
|
||||||
|
*/
|
||||||
|
std::string ToString(const Conv & conv) const
|
||||||
|
{
|
||||||
|
std::string result;
|
||||||
|
ToStringBase<std::string, char>(result, conv);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*!
|
||||||
|
a method for converting into a string
|
||||||
|
struct Conv is defined in ttmathtypes.h, look there for more information about parameters
|
||||||
|
*/
|
||||||
|
std::string ToString() const
|
||||||
|
{
|
||||||
|
Conv conv;
|
||||||
|
|
||||||
|
return ToString(conv);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
|
||||||
|
/*!
|
||||||
|
an auxiliary method for converting into the string
|
||||||
|
*/
|
||||||
template<class string_type, class char_type>
|
template<class string_type, class char_type>
|
||||||
uint ToStringBase( string_type & result,
|
uint ToStringBase(string_type & result, const Conv & conv) const
|
||||||
uint base,
|
|
||||||
bool always_scientific,
|
|
||||||
sint when_scientific,
|
|
||||||
sint max_digit_after_comma,
|
|
||||||
bool remove_trailing_zeroes,
|
|
||||||
char_type decimal_point) const
|
|
||||||
{
|
{
|
||||||
static char error_overflow_msg[] = "overflow";
|
static char error_overflow_msg[] = "overflow";
|
||||||
static char error_nan_msg[] = "NaN";
|
static char error_nan_msg[] = "NaN";
|
||||||
|
@ -2896,7 +2928,7 @@ private:
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if( base<2 || base>16 )
|
if( conv.base<2 || conv.base>16 )
|
||||||
{
|
{
|
||||||
Misc::AssignString(result, error_overflow_msg);
|
Misc::AssignString(result, error_overflow_msg);
|
||||||
return 1;
|
return 1;
|
||||||
|
@ -2926,7 +2958,7 @@ private:
|
||||||
*/
|
*/
|
||||||
Int<exp+1> new_exp;
|
Int<exp+1> new_exp;
|
||||||
|
|
||||||
if( ToString_CreateNewMantissaAndExponent(result, base, new_exp) )
|
if( ToString_CreateNewMantissaAndExponent(result, conv, new_exp) )
|
||||||
{
|
{
|
||||||
Misc::AssignString(result, error_overflow_msg);
|
Misc::AssignString(result, error_overflow_msg);
|
||||||
return 1;
|
return 1;
|
||||||
|
@ -2936,16 +2968,14 @@ private:
|
||||||
we're rounding the mantissa only if the base is different from 2,4,8 or 16
|
we're rounding the mantissa only if the base is different from 2,4,8 or 16
|
||||||
(this formula means that the number of bits in the base is greater than one)
|
(this formula means that the number of bits in the base is greater than one)
|
||||||
*/
|
*/
|
||||||
if( base!=2 && base!=4 && base!=8 && base!=16 )
|
if( conv.base!=2 && conv.base!=4 && conv.base!=8 && conv.base!=16 )
|
||||||
if( ToString_RoundMantissa(result, base, new_exp, decimal_point) )
|
if( ToString_RoundMantissa<string_type, char_type>(result, conv, new_exp) )
|
||||||
{
|
{
|
||||||
Misc::AssignString(result, error_overflow_msg);
|
Misc::AssignString(result, error_overflow_msg);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if( ToString_SetCommaAndExponent( result, base, new_exp, always_scientific,
|
if( ToString_SetCommaAndExponent<string_type, char_type>(result, conv, new_exp) )
|
||||||
when_scientific, max_digit_after_comma,
|
|
||||||
remove_trailing_zeroes, decimal_point ) )
|
|
||||||
{
|
{
|
||||||
Misc::AssignString(result, error_overflow_msg);
|
Misc::AssignString(result, error_overflow_msg);
|
||||||
return 1;
|
return 1;
|
||||||
|
@ -2959,8 +2989,6 @@ private:
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private:
|
|
||||||
|
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
in the method 'ToString_CreateNewMantissaAndExponent()' we're using
|
in the method 'ToString_CreateNewMantissaAndExponent()' we're using
|
||||||
|
@ -2971,7 +2999,7 @@ private:
|
||||||
|
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
an auxiliary method for converting into the string (private)
|
an auxiliary method for converting into the string
|
||||||
|
|
||||||
input:
|
input:
|
||||||
base - the base in range <2,16>
|
base - the base in range <2,16>
|
||||||
|
@ -3030,16 +3058,16 @@ private:
|
||||||
new_exp = [log base (2^exponent)] + 1 <- where [x] means integer value from x
|
new_exp = [log base (2^exponent)] + 1 <- where [x] means integer value from x
|
||||||
*/
|
*/
|
||||||
template<class string_type>
|
template<class string_type>
|
||||||
uint ToString_CreateNewMantissaAndExponent( string_type & new_man, uint base,
|
uint ToString_CreateNewMantissaAndExponent( string_type & new_man, const Conv & conv,
|
||||||
Int<exp+1> & new_exp) const
|
Int<exp+1> & new_exp) const
|
||||||
{
|
{
|
||||||
uint c = 0;
|
uint c = 0;
|
||||||
|
|
||||||
if(base<2 || base>16)
|
if( conv.base<2 || conv.base>16 )
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
// the speciality for base equal 2
|
// the speciality for base equal 2
|
||||||
if( base == 2 )
|
if( conv.base == 2 )
|
||||||
return ToString_CreateNewMantissaAndExponent_Base2(new_man, new_exp);
|
return ToString_CreateNewMantissaAndExponent_Base2(new_man, new_exp);
|
||||||
|
|
||||||
// this = mantissa * 2^exponent
|
// this = mantissa * 2^exponent
|
||||||
|
@ -3054,7 +3082,7 @@ private:
|
||||||
|
|
||||||
// new_exp_ = [log base (2^exponent)] + 1
|
// new_exp_ = [log base (2^exponent)] + 1
|
||||||
Big<exp+1,man> new_exp_;
|
Big<exp+1,man> new_exp_;
|
||||||
c += new_exp_.ToString_Log(temp, base); // this logarithm isn't very complicated
|
c += new_exp_.ToString_Log(temp, conv.base); // this logarithm isn't very complicated
|
||||||
new_exp_.SkipFraction();
|
new_exp_.SkipFraction();
|
||||||
temp.SetOne();
|
temp.SetOne();
|
||||||
c += new_exp_.Add( temp );
|
c += new_exp_.Add( temp );
|
||||||
|
@ -3067,7 +3095,7 @@ private:
|
||||||
c += new_exp_.ToInt(new_exp);
|
c += new_exp_.ToInt(new_exp);
|
||||||
|
|
||||||
// base_ = base
|
// base_ = base
|
||||||
Big<exp+1,man> base_(base);
|
Big<exp+1,man> base_(conv.base);
|
||||||
|
|
||||||
// base_ = base_ ^ new_exp_
|
// base_ = base_ ^ new_exp_
|
||||||
c += base_.Pow( new_exp_ );
|
c += base_.Pow( new_exp_ );
|
||||||
|
@ -3089,7 +3117,7 @@ private:
|
||||||
// (temp.Div( base_ )) the value of exponent should be equal zero or
|
// (temp.Div( base_ )) the value of exponent should be equal zero or
|
||||||
// minimum smaller than zero then we've got the mantissa which has
|
// minimum smaller than zero then we've got the mantissa which has
|
||||||
// maximum valid bits
|
// maximum valid bits
|
||||||
temp.mantissa.ToString(new_man, base);
|
temp.mantissa.ToString(new_man, conv.base);
|
||||||
|
|
||||||
// because we had used a bigger type for calculating I think we
|
// because we had used a bigger type for calculating I think we
|
||||||
// shouldn't have had a carry
|
// shouldn't have had a carry
|
||||||
|
@ -3307,7 +3335,7 @@ private:
|
||||||
(it's used in systems where the base is different from 2)
|
(it's used in systems where the base is different from 2)
|
||||||
*/
|
*/
|
||||||
template<class string_type, class char_type>
|
template<class string_type, class char_type>
|
||||||
uint ToString_RoundMantissa(string_type & new_man, uint base, Int<exp+1> & new_exp, char_type decimal_point) const
|
uint ToString_RoundMantissa(string_type & new_man, const Conv & conv, Int<exp+1> & new_exp) const
|
||||||
{
|
{
|
||||||
// we must have minimum two characters
|
// we must have minimum two characters
|
||||||
if( new_man.length() < 2 )
|
if( new_man.length() < 2 )
|
||||||
|
@ -3322,8 +3350,8 @@ private:
|
||||||
|
|
||||||
// if the last character is greater or equal 'base/2'
|
// if the last character is greater or equal 'base/2'
|
||||||
// we'll add one into the new mantissa
|
// we'll add one into the new mantissa
|
||||||
if( digit >= base / 2 )
|
if( digit >= conv.base / 2 )
|
||||||
ToString_RoundMantissa_AddOneIntoMantissa(new_man, base, decimal_point);
|
ToString_RoundMantissa_AddOneIntoMantissa<string_type, char_type>(new_man, conv);
|
||||||
|
|
||||||
return carry;
|
return carry;
|
||||||
}
|
}
|
||||||
|
@ -3335,7 +3363,7 @@ private:
|
||||||
this method addes one into the new mantissa
|
this method addes one into the new mantissa
|
||||||
*/
|
*/
|
||||||
template<class string_type, class char_type>
|
template<class string_type, class char_type>
|
||||||
void ToString_RoundMantissa_AddOneIntoMantissa(string_type & new_man, uint base, char_type decimal_point) const
|
void ToString_RoundMantissa_AddOneIntoMantissa(string_type & new_man, const Conv & conv) const
|
||||||
{
|
{
|
||||||
if( new_man.empty() )
|
if( new_man.empty() )
|
||||||
return;
|
return;
|
||||||
|
@ -3348,13 +3376,13 @@ private:
|
||||||
// we can have the comma as well because
|
// we can have the comma as well because
|
||||||
// we're using this method later in ToString_CorrectDigitsAfterComma_Round()
|
// we're using this method later in ToString_CorrectDigitsAfterComma_Round()
|
||||||
// (we're only ignoring it)
|
// (we're only ignoring it)
|
||||||
if( new_man[i] == decimal_point )
|
if( new_man[i] == static_cast<char_type>(conv.comma) )
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
// we're adding one
|
// we're adding one
|
||||||
uint digit = Misc::CharToDigit( new_man[i] ) + 1;
|
uint digit = Misc::CharToDigit( new_man[i] ) + 1;
|
||||||
|
|
||||||
if( digit == base )
|
if( digit == conv.base )
|
||||||
digit = 0;
|
digit = 0;
|
||||||
else
|
else
|
||||||
was_carry = false;
|
was_carry = false;
|
||||||
|
@ -3374,13 +3402,7 @@ private:
|
||||||
into the string
|
into the string
|
||||||
*/
|
*/
|
||||||
template<class string_type, class char_type>
|
template<class string_type, class char_type>
|
||||||
uint ToString_SetCommaAndExponent( string_type & new_man, uint base,
|
uint ToString_SetCommaAndExponent(string_type & new_man, const Conv & conv, Int<exp+1> & new_exp) const
|
||||||
Int<exp+1> & new_exp,
|
|
||||||
bool always_scientific,
|
|
||||||
sint when_scientific,
|
|
||||||
sint max_digit_after_comma,
|
|
||||||
bool remove_trailing_zeroes,
|
|
||||||
char_type decimal_point) const
|
|
||||||
{
|
{
|
||||||
uint carry = 0;
|
uint carry = 0;
|
||||||
|
|
||||||
|
@ -3399,18 +3421,19 @@ private:
|
||||||
// there shouldn't have been a carry because we're using
|
// there shouldn't have been a carry because we're using
|
||||||
// a greater type -- 'Int<exp+1>' instead of 'Int<exp>'
|
// a greater type -- 'Int<exp+1>' instead of 'Int<exp>'
|
||||||
|
|
||||||
if( !always_scientific )
|
bool print_scientific = conv.scient;
|
||||||
|
|
||||||
|
if( !print_scientific )
|
||||||
{
|
{
|
||||||
if( scientific_exp > when_scientific || scientific_exp < -sint(when_scientific) )
|
if( scientific_exp > conv.scient_from || scientific_exp < -sint(conv.scient_from) )
|
||||||
always_scientific = true;
|
print_scientific = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 'always_scientific' could be changed
|
if( !print_scientific )
|
||||||
if( !always_scientific )
|
ToString_SetCommaAndExponent_Normal<string_type, char_type>(new_man, conv, new_exp);
|
||||||
ToString_SetCommaAndExponent_Normal(new_man, base, new_exp, max_digit_after_comma, remove_trailing_zeroes, decimal_point);
|
|
||||||
else
|
else
|
||||||
// we're passing the 'scientific_exp' instead of 'new_exp' here
|
// we're passing the 'scientific_exp' instead of 'new_exp' here
|
||||||
ToString_SetCommaAndExponent_Scientific(new_man, base, scientific_exp, max_digit_after_comma, remove_trailing_zeroes, decimal_point);
|
ToString_SetCommaAndExponent_Scientific<string_type, char_type>(new_man, conv, scientific_exp);
|
||||||
|
|
||||||
return (carry==0)? 0 : 1;
|
return (carry==0)? 0 : 1;
|
||||||
}
|
}
|
||||||
|
@ -3420,25 +3443,22 @@ private:
|
||||||
an auxiliary method for converting into the string
|
an auxiliary method for converting into the string
|
||||||
*/
|
*/
|
||||||
template<class string_type, class char_type>
|
template<class string_type, class char_type>
|
||||||
void ToString_SetCommaAndExponent_Normal(
|
void ToString_SetCommaAndExponent_Normal(string_type & new_man, const Conv & conv, Int<exp+1> & new_exp ) const
|
||||||
string_type & new_man,
|
|
||||||
uint base,
|
|
||||||
Int<exp+1> & new_exp,
|
|
||||||
sint max_digit_after_comma,
|
|
||||||
bool remove_trailing_zeroes,
|
|
||||||
char_type decimal_point) const
|
|
||||||
{
|
{
|
||||||
if( !new_exp.IsSign() ) //if( new_exp >= 0 )
|
if( !new_exp.IsSign() ) // it means: if( new_exp >= 0 )
|
||||||
return ToString_SetCommaAndExponent_Normal_AddingZero(new_man, new_exp);
|
ToString_SetCommaAndExponent_Normal_AddingZero<string_type, char_type>(new_man, new_exp);
|
||||||
else
|
else
|
||||||
return ToString_SetCommaAndExponent_Normal_SetCommaInside(new_man, base, new_exp, max_digit_after_comma, remove_trailing_zeroes, decimal_point);
|
ToString_SetCommaAndExponent_Normal_SetCommaInside<string_type, char_type>(new_man, conv, new_exp);
|
||||||
|
|
||||||
|
|
||||||
|
ToString_Group_man<string_type, char_type>(new_man, conv);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
an auxiliary method for converting into the string
|
an auxiliary method for converting into the string
|
||||||
*/
|
*/
|
||||||
template<class string_type>
|
template<class string_type, class char_type>
|
||||||
void ToString_SetCommaAndExponent_Normal_AddingZero(string_type & new_man,
|
void ToString_SetCommaAndExponent_Normal_AddingZero(string_type & new_man,
|
||||||
Int<exp+1> & new_exp) const
|
Int<exp+1> & new_exp) const
|
||||||
{
|
{
|
||||||
|
@ -3460,12 +3480,9 @@ private:
|
||||||
*/
|
*/
|
||||||
template<class string_type, class char_type>
|
template<class string_type, class char_type>
|
||||||
void ToString_SetCommaAndExponent_Normal_SetCommaInside(
|
void ToString_SetCommaAndExponent_Normal_SetCommaInside(
|
||||||
string_type & new_man,
|
string_type & new_man,
|
||||||
uint base,
|
const Conv & conv,
|
||||||
Int<exp+1> & new_exp,
|
Int<exp+1> & new_exp ) const
|
||||||
sint max_digit_after_comma,
|
|
||||||
bool remove_trailing_zeroes,
|
|
||||||
char_type decimal_point) const
|
|
||||||
{
|
{
|
||||||
// new_exp is < 0
|
// new_exp is < 0
|
||||||
|
|
||||||
|
@ -3477,7 +3494,7 @@ private:
|
||||||
// we're setting the comma within the mantissa
|
// we're setting the comma within the mantissa
|
||||||
|
|
||||||
sint index = new_man_len - e;
|
sint index = new_man_len - e;
|
||||||
new_man.insert( new_man.begin() + index, decimal_point);
|
new_man.insert( new_man.begin() + index, static_cast<char_type>(conv.comma));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -3486,11 +3503,11 @@ private:
|
||||||
uint how_many = e - new_man_len;
|
uint how_many = e - new_man_len;
|
||||||
string_type man_temp(how_many+1, '0');
|
string_type man_temp(how_many+1, '0');
|
||||||
|
|
||||||
man_temp.insert( man_temp.begin()+1, decimal_point);
|
man_temp.insert( man_temp.begin()+1, static_cast<char_type>(conv.comma));
|
||||||
new_man.insert(0, man_temp);
|
new_man.insert(0, man_temp);
|
||||||
}
|
}
|
||||||
|
|
||||||
ToString_CorrectDigitsAfterComma(new_man, base, max_digit_after_comma, remove_trailing_zeroes, decimal_point);
|
ToString_CorrectDigitsAfterComma<string_type, char_type>(new_man, conv);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -3499,20 +3516,18 @@ private:
|
||||||
*/
|
*/
|
||||||
template<class string_type, class char_type>
|
template<class string_type, class char_type>
|
||||||
void ToString_SetCommaAndExponent_Scientific( string_type & new_man,
|
void ToString_SetCommaAndExponent_Scientific( string_type & new_man,
|
||||||
uint base,
|
const Conv & conv,
|
||||||
Int<exp+1> & scientific_exp,
|
Int<exp+1> & scientific_exp ) const
|
||||||
sint max_digit_after_comma,
|
|
||||||
bool remove_trailing_zeroes,
|
|
||||||
char_type decimal_point) const
|
|
||||||
{
|
{
|
||||||
if( new_man.empty() )
|
if( new_man.empty() )
|
||||||
return;
|
return;
|
||||||
|
|
||||||
new_man.insert( new_man.begin()+1, decimal_point );
|
new_man.insert( new_man.begin()+1, static_cast<char_type>(conv.comma) );
|
||||||
|
|
||||||
ToString_CorrectDigitsAfterComma(new_man, base, max_digit_after_comma, remove_trailing_zeroes, decimal_point);
|
ToString_CorrectDigitsAfterComma<string_type, char_type>(new_man, conv);
|
||||||
|
ToString_Group_man<string_type, char_type>(new_man, conv);
|
||||||
if( base == 10 )
|
|
||||||
|
if( conv.base == 10 )
|
||||||
{
|
{
|
||||||
new_man += 'e';
|
new_man += 'e';
|
||||||
|
|
||||||
|
@ -3527,7 +3542,7 @@ private:
|
||||||
}
|
}
|
||||||
|
|
||||||
string_type temp_exp;
|
string_type temp_exp;
|
||||||
scientific_exp.ToString( temp_exp, base );
|
scientific_exp.ToString( temp_exp, conv.base );
|
||||||
|
|
||||||
new_man += temp_exp;
|
new_man += temp_exp;
|
||||||
}
|
}
|
||||||
|
@ -3537,17 +3552,84 @@ private:
|
||||||
an auxiliary method for converting into the string
|
an auxiliary method for converting into the string
|
||||||
*/
|
*/
|
||||||
template<class string_type, class char_type>
|
template<class string_type, class char_type>
|
||||||
void ToString_CorrectDigitsAfterComma( string_type & new_man,
|
void ToString_Group_man(string_type & new_man, const Conv & conv) const
|
||||||
uint base,
|
|
||||||
sint max_digit_after_comma,
|
|
||||||
bool remove_trailing_zeroes,
|
|
||||||
char_type decimal_point) const
|
|
||||||
{
|
{
|
||||||
if( max_digit_after_comma >= 0 )
|
typedef typename string_type::size_type StrSize;
|
||||||
ToString_CorrectDigitsAfterComma_Round(new_man, base, max_digit_after_comma, decimal_point);
|
|
||||||
|
|
||||||
if( remove_trailing_zeroes )
|
if( conv.group == 0 )
|
||||||
ToString_CorrectDigitsAfterComma_CutOffZeroCharacters(new_man, decimal_point);
|
return;
|
||||||
|
|
||||||
|
// first we're looking for the comma operator
|
||||||
|
StrSize index = new_man.find(static_cast<char_type>(conv.comma), 0);
|
||||||
|
|
||||||
|
if( index == string_type::npos )
|
||||||
|
index = new_man.size();
|
||||||
|
|
||||||
|
ToString_Group_man_before_comma<string_type, char_type>(new_man, conv, index);
|
||||||
|
ToString_Group_man_after_comma<string_type, char_type>(new_man, conv, index+1);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*!
|
||||||
|
an auxiliary method for converting into the string
|
||||||
|
*/
|
||||||
|
template<class string_type, class char_type>
|
||||||
|
void ToString_Group_man_before_comma( string_type & new_man, const Conv & conv,
|
||||||
|
typename string_type::size_type & index) const
|
||||||
|
{
|
||||||
|
typedef typename string_type::size_type StrSize;
|
||||||
|
uint group = 0;
|
||||||
|
|
||||||
|
StrSize i = index;
|
||||||
|
|
||||||
|
// adding group characters before the comma operator
|
||||||
|
// i>0 because on the first position we don't put any additional grouping characters
|
||||||
|
for( ; i>0 ; --i, ++group)
|
||||||
|
{
|
||||||
|
if( group >= 3 )
|
||||||
|
{
|
||||||
|
group = 0;
|
||||||
|
new_man.insert(i, 1, static_cast<char_type>(conv.group));
|
||||||
|
++index;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*!
|
||||||
|
an auxiliary method for converting into the string
|
||||||
|
*/
|
||||||
|
template<class string_type, class char_type>
|
||||||
|
void ToString_Group_man_after_comma(string_type & new_man, const Conv & conv,
|
||||||
|
typename string_type::size_type index) const
|
||||||
|
{
|
||||||
|
uint group = 0;
|
||||||
|
|
||||||
|
for( ; index<new_man.size() ; ++index, ++group)
|
||||||
|
{
|
||||||
|
if( group >= 3 )
|
||||||
|
{
|
||||||
|
group = 0;
|
||||||
|
new_man.insert(index, 1, static_cast<char_type>(conv.group));
|
||||||
|
++index;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*!
|
||||||
|
an auxiliary method for converting into the string
|
||||||
|
*/
|
||||||
|
template<class string_type, class char_type>
|
||||||
|
void ToString_CorrectDigitsAfterComma( string_type & new_man,
|
||||||
|
const Conv & conv ) const
|
||||||
|
{
|
||||||
|
if( conv.comma_digits >= 0 )
|
||||||
|
ToString_CorrectDigitsAfterComma_Round<string_type, char_type>(new_man, conv);
|
||||||
|
|
||||||
|
if( conv.trim_zeroes )
|
||||||
|
ToString_CorrectDigitsAfterComma_CutOffZeroCharacters<string_type, char_type>(new_man, conv);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -3557,7 +3639,7 @@ private:
|
||||||
template<class string_type, class char_type>
|
template<class string_type, class char_type>
|
||||||
void ToString_CorrectDigitsAfterComma_CutOffZeroCharacters(
|
void ToString_CorrectDigitsAfterComma_CutOffZeroCharacters(
|
||||||
string_type & new_man,
|
string_type & new_man,
|
||||||
char_type decimal_point) const
|
const Conv & conv) const
|
||||||
{
|
{
|
||||||
// minimum two characters
|
// minimum two characters
|
||||||
if( new_man.length() < 2 )
|
if( new_man.length() < 2 )
|
||||||
|
@ -3575,12 +3657,12 @@ private:
|
||||||
// we must have a comma
|
// we must have a comma
|
||||||
// (the comma can be removed by ToString_CorrectDigitsAfterComma_Round
|
// (the comma can be removed by ToString_CorrectDigitsAfterComma_Round
|
||||||
// which is called before)
|
// which is called before)
|
||||||
if( new_man.find_last_of(decimal_point, i) == string_type::npos )
|
if( new_man.find_last_of(static_cast<char_type>(conv.comma), i) == string_type::npos )
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// if directly before the first zero is the comma operator
|
// if directly before the first zero is the comma operator
|
||||||
// we're cutting it as well
|
// we're cutting it as well
|
||||||
if( i>0 && new_man[i]==decimal_point )
|
if( i>0 && new_man[i]==static_cast<char_type>(conv.comma) )
|
||||||
--i;
|
--i;
|
||||||
|
|
||||||
new_man.erase(i+1, new_man.length()-i-1);
|
new_man.erase(i+1, new_man.length()-i-1);
|
||||||
|
@ -3593,12 +3675,12 @@ private:
|
||||||
template<class string_type, class char_type>
|
template<class string_type, class char_type>
|
||||||
void ToString_CorrectDigitsAfterComma_Round(
|
void ToString_CorrectDigitsAfterComma_Round(
|
||||||
string_type & new_man,
|
string_type & new_man,
|
||||||
uint base,
|
const Conv & conv ) const
|
||||||
sint max_digit_after_comma,
|
|
||||||
char_type decimal_point) const
|
|
||||||
{
|
{
|
||||||
|
typedef typename string_type::size_type StrSize;
|
||||||
|
|
||||||
// first we're looking for the comma operator
|
// first we're looking for the comma operator
|
||||||
typename string_type::size_type index = new_man.find(decimal_point, 0);
|
StrSize index = new_man.find(static_cast<char_type>(conv.comma), 0);
|
||||||
|
|
||||||
if( index == string_type::npos )
|
if( index == string_type::npos )
|
||||||
// nothing was found (actually there can't be this situation)
|
// nothing was found (actually there can't be this situation)
|
||||||
|
@ -3607,45 +3689,141 @@ private:
|
||||||
// we're calculating how many digits there are at the end (after the comma)
|
// we're calculating how many digits there are at the end (after the comma)
|
||||||
// 'after_comma' will be greater than zero because at the end
|
// 'after_comma' will be greater than zero because at the end
|
||||||
// we have at least one digit
|
// we have at least one digit
|
||||||
typename string_type::size_type after_comma = new_man.length() - index - 1;
|
StrSize after_comma = new_man.length() - index - 1;
|
||||||
|
|
||||||
// if 'max_digit_after_comma' is greater than 'after_comma' (or equal)
|
// if 'max_digit_after_comma' is greater than 'after_comma' (or equal)
|
||||||
// we don't have anything for cutting
|
// we don't have anything for cutting
|
||||||
if( static_cast<typename string_type::size_type>(max_digit_after_comma) >= after_comma )
|
if( static_cast<StrSize>(conv.comma_digits) >= after_comma )
|
||||||
return;
|
return;
|
||||||
|
|
||||||
uint last_digit = Misc::CharToDigit( new_man[ index + max_digit_after_comma + 1 ], base );
|
uint last_digit = Misc::CharToDigit( new_man[ index + conv.comma_digits + 1 ], conv.base );
|
||||||
|
|
||||||
// we're cutting the rest of the string
|
// we're cutting the rest of the string
|
||||||
new_man.erase(index + max_digit_after_comma + 1, after_comma - max_digit_after_comma);
|
new_man.erase(index + conv.comma_digits + 1, after_comma - conv.comma_digits);
|
||||||
|
|
||||||
if( max_digit_after_comma == 0 )
|
if( conv.comma_digits == 0 )
|
||||||
{
|
{
|
||||||
// we're cutting the comma operator as well
|
// we're cutting the comma operator as well
|
||||||
// (it's not needed now because we've cut the whole rest after the comma)
|
// (it's not needed now because we've cut the whole rest after the comma)
|
||||||
new_man.erase(index, 1);
|
new_man.erase(index, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
if( last_digit >= base / 2 )
|
if( last_digit >= conv.base / 2 )
|
||||||
// we must round here
|
// we must round here
|
||||||
ToString_RoundMantissa_AddOneIntoMantissa(new_man, base, decimal_point);
|
ToString_RoundMantissa_AddOneIntoMantissa<string_type, char_type>(new_man, conv);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
/*!
|
||||||
|
a method for converting a string into its value
|
||||||
|
|
||||||
|
it returns 1 if the value is too big -- we cannot pass it into the range
|
||||||
|
of our class Big<exp,man> (or if the base is incorrect)
|
||||||
|
|
||||||
|
that means only digits before the comma operator can make this value too big,
|
||||||
|
all digits after the comma we can ignore
|
||||||
|
|
||||||
|
'source' - pointer to the string for parsing
|
||||||
|
|
||||||
|
if 'after_source' is set that when this method finishes
|
||||||
|
it sets the pointer to the new first character after parsed value
|
||||||
|
|
||||||
|
'value_read' - if the pointer is provided that means the value_read will be true
|
||||||
|
only when a value has been actually read, there can be situation where only such
|
||||||
|
a string '-' or '+' will be parsed -- 'after_source' will be different from 'source' but
|
||||||
|
no value has been read (there are no digits)
|
||||||
|
on other words if 'value_read' is true -- there is at least one digit in the string
|
||||||
|
*/
|
||||||
|
uint FromString(const char * source, uint base = 10, const char ** after_source = 0, bool * value_read = 0)
|
||||||
|
{
|
||||||
|
Conv conv;
|
||||||
|
conv.base = base;
|
||||||
|
|
||||||
|
return FromStringBase(source, conv, after_source, value_read);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*!
|
||||||
|
a method for converting a string into its value
|
||||||
|
*/
|
||||||
|
uint FromString(const wchar_t * source, uint base = 10, const wchar_t ** after_source = 0, bool * value_read = 0)
|
||||||
|
{
|
||||||
|
Conv conv;
|
||||||
|
conv.base = base;
|
||||||
|
|
||||||
|
return FromStringBase(source, conv, after_source, value_read);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*!
|
||||||
|
a method for converting a string into its value
|
||||||
|
*/
|
||||||
|
uint FromString(const char * source, const Conv & conv, const char ** after_source = 0, bool * value_read = 0)
|
||||||
|
{
|
||||||
|
return FromStringBase(source, conv, after_source, value_read);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*!
|
||||||
|
a method for converting a string into its value
|
||||||
|
*/
|
||||||
|
uint FromString(const wchar_t * source, const Conv & conv, const wchar_t ** after_source = 0, bool * value_read = 0)
|
||||||
|
{
|
||||||
|
return FromStringBase(source, conv, after_source, value_read);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*!
|
||||||
|
a method for converting a string into its value
|
||||||
|
*/
|
||||||
|
uint FromString(const std::string & string, uint base = 10, const wchar_t ** after_source = 0, bool * value_read = 0)
|
||||||
|
{
|
||||||
|
return FromString(string.c_str(), base, after_source, value_read);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*!
|
||||||
|
a method for converting a string into its value
|
||||||
|
*/
|
||||||
|
uint FromString(const std::wstring & string, uint base = 10, const wchar_t ** after_source = 0, bool * value_read = 0)
|
||||||
|
{
|
||||||
|
return FromString(string.c_str(), base, after_source, value_read);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*!
|
||||||
|
a method for converting a string into its value
|
||||||
|
*/
|
||||||
|
uint FromString(const std::string & string, const Conv & conv, const wchar_t ** after_source = 0, bool * value_read = 0)
|
||||||
|
{
|
||||||
|
return FromString(string.c_str(), conv, after_source, value_read);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*!
|
||||||
|
a method for converting a string into its value
|
||||||
|
*/
|
||||||
|
uint FromString(const std::wstring & string, const Conv & conv, const wchar_t ** after_source = 0, bool * value_read = 0)
|
||||||
|
{
|
||||||
|
return FromString(string.c_str(), conv, after_source, value_read);
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
an auxiliary method for converting from a string
|
an auxiliary method for converting from a string
|
||||||
*/
|
*/
|
||||||
template<class char_type>
|
template<class char_type>
|
||||||
uint FromStringBase(const char_type * source, uint base = 10, const char_type ** after_source = 0, bool * value_read = 0)
|
uint FromStringBase(const char_type * source, const Conv & conv, const char_type ** after_source = 0, bool * value_read = 0)
|
||||||
{
|
{
|
||||||
bool is_sign;
|
bool is_sign;
|
||||||
bool value_read_temp = false;
|
bool value_read_temp = false;
|
||||||
|
|
||||||
if( base<2 || base>16 )
|
if( conv.base<2 || conv.base>16 )
|
||||||
{
|
{
|
||||||
SetNan();
|
SetNan();
|
||||||
|
|
||||||
|
@ -3661,12 +3839,12 @@ private:
|
||||||
SetZero();
|
SetZero();
|
||||||
FromString_TestSign( source, is_sign );
|
FromString_TestSign( source, is_sign );
|
||||||
|
|
||||||
uint c = FromString_ReadPartBeforeComma( source, base, value_read_temp );
|
uint c = FromString_ReadPartBeforeComma( source, conv, value_read_temp );
|
||||||
|
|
||||||
if( FromString_TestCommaOperator(source) )
|
if( FromString_TestCommaOperator(source, conv) )
|
||||||
c += FromString_ReadPartAfterComma( source, base, value_read_temp );
|
c += FromString_ReadPartAfterComma( source, conv, value_read_temp );
|
||||||
|
|
||||||
if( value_read_temp && base == 10 )
|
if( value_read_temp && conv.base == 10 )
|
||||||
c += FromString_ReadScientificIfExists( source );
|
c += FromString_ReadScientificIfExists( source );
|
||||||
|
|
||||||
if( is_sign && !IsZero() )
|
if( is_sign && !IsZero() )
|
||||||
|
@ -3682,48 +3860,6 @@ private:
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
/*!
|
|
||||||
a method for converting a string into its value
|
|
||||||
|
|
||||||
it returns 1 if the value will be too big -- we cannot pass it into the range
|
|
||||||
of our class Big<exp,man> (or if the base is incorrect)
|
|
||||||
|
|
||||||
that means only digits before the comma operator can make this value too big,
|
|
||||||
all digits after the comma we can ignore
|
|
||||||
|
|
||||||
'source' - pointer to the string for parsing
|
|
||||||
'const char*' or 'const wchar_t*'
|
|
||||||
|
|
||||||
if 'after_source' is set that when this method finishes
|
|
||||||
it sets the pointer to the new first character after parsed value
|
|
||||||
|
|
||||||
'value_read' - if the pointer is provided that means the value_read will be true
|
|
||||||
only when a value has been actually read, there can be situation where only such
|
|
||||||
a string '-' or '+' will be parsed -- 'after_source' will be different from 'source' but
|
|
||||||
no value has been read (there are no digits)
|
|
||||||
on other words if 'value_read' is true -- there is at least one digit in the string
|
|
||||||
*/
|
|
||||||
uint FromString(const char * source, uint base = 10, const char ** after_source = 0, bool * value_read = 0)
|
|
||||||
{
|
|
||||||
return FromStringBase(source, base, after_source, value_read);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*!
|
|
||||||
a method for converting a string into its value
|
|
||||||
*/
|
|
||||||
uint FromString(const wchar_t * source, uint base = 10, const wchar_t ** after_source = 0, bool * value_read = 0)
|
|
||||||
{
|
|
||||||
return FromStringBase(source, base, after_source, value_read);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private:
|
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
we're testing whether the value is with the sign
|
we're testing whether the value is with the sign
|
||||||
|
|
||||||
|
@ -3753,10 +3889,10 @@ private:
|
||||||
we're testing whether there's a comma operator
|
we're testing whether there's a comma operator
|
||||||
*/
|
*/
|
||||||
template<class char_type>
|
template<class char_type>
|
||||||
bool FromString_TestCommaOperator(const char_type * & source)
|
bool FromString_TestCommaOperator(const char_type * & source, const Conv & conv)
|
||||||
{
|
{
|
||||||
if( (*source == TTMATH_COMMA_CHARACTER_1) ||
|
if( (*source == static_cast<char_type>(conv.comma)) ||
|
||||||
(*source == TTMATH_COMMA_CHARACTER_2 && TTMATH_COMMA_CHARACTER_2 != 0 ) )
|
(*source == static_cast<char_type>(conv.comma2) && conv.comma2 != 0 ) )
|
||||||
{
|
{
|
||||||
++source;
|
++source;
|
||||||
|
|
||||||
|
@ -3772,18 +3908,25 @@ private:
|
||||||
(before the comma operator)
|
(before the comma operator)
|
||||||
*/
|
*/
|
||||||
template<class char_type>
|
template<class char_type>
|
||||||
uint FromString_ReadPartBeforeComma( const char_type * & source, uint base, bool & value_read )
|
uint FromString_ReadPartBeforeComma( const char_type * & source, const Conv & conv, bool & value_read )
|
||||||
{
|
{
|
||||||
sint character;
|
sint character;
|
||||||
Big<exp, man> temp;
|
Big<exp, man> temp;
|
||||||
Big<exp, man> base_( base );
|
Big<exp, man> base_( conv.base );
|
||||||
|
|
||||||
Misc::SkipWhiteCharacters( source );
|
Misc::SkipWhiteCharacters( source );
|
||||||
|
|
||||||
for( ; (character=Misc::CharToDigit(*source, base)) != -1 ; ++source )
|
for( ; true ; ++source )
|
||||||
{
|
{
|
||||||
value_read = true;
|
if( conv.group!=0 && *source==static_cast<char>(conv.group) )
|
||||||
|
continue;
|
||||||
|
|
||||||
|
character = Misc::CharToDigit(*source, conv.base);
|
||||||
|
|
||||||
|
if( character == -1 )
|
||||||
|
break;
|
||||||
|
|
||||||
|
value_read = true;
|
||||||
temp = character;
|
temp = character;
|
||||||
|
|
||||||
if( Mul(base_) )
|
if( Mul(base_) )
|
||||||
|
@ -3802,11 +3945,11 @@ private:
|
||||||
(after the comma operator)
|
(after the comma operator)
|
||||||
*/
|
*/
|
||||||
template<class char_type>
|
template<class char_type>
|
||||||
uint FromString_ReadPartAfterComma( const char_type * & source, uint base, bool & value_read )
|
uint FromString_ReadPartAfterComma( const char_type * & source, const Conv & conv, bool & value_read )
|
||||||
{
|
{
|
||||||
sint character;
|
sint character;
|
||||||
uint c = 0, index = 1;
|
uint c = 0, index = 1;
|
||||||
Big<exp, man> part, power, old_value, base_( base );
|
Big<exp, man> part, power, old_value, base_( conv.base );
|
||||||
|
|
||||||
// we don't remove any white characters here
|
// we don't remove any white characters here
|
||||||
|
|
||||||
|
@ -3816,8 +3959,16 @@ private:
|
||||||
|
|
||||||
power.SetOne();
|
power.SetOne();
|
||||||
|
|
||||||
for( ; (character=Misc::CharToDigit(*source, base)) != -1 ; ++source, ++index )
|
for( ; true ; ++source, ++index )
|
||||||
{
|
{
|
||||||
|
if( conv.group!=0 && *source==static_cast<char>(conv.group) )
|
||||||
|
continue;
|
||||||
|
|
||||||
|
character = Misc::CharToDigit(*source, conv.base);
|
||||||
|
|
||||||
|
if( character == -1 )
|
||||||
|
break;
|
||||||
|
|
||||||
value_read = true;
|
value_read = true;
|
||||||
|
|
||||||
part = character;
|
part = character;
|
||||||
|
@ -3849,7 +4000,7 @@ private:
|
||||||
// we could break the parsing somewhere in the middle of the string,
|
// we could break the parsing somewhere in the middle of the string,
|
||||||
// but the result (value) still can be good
|
// but the result (value) still can be good
|
||||||
// we should set a correct value of 'source' now
|
// we should set a correct value of 'source' now
|
||||||
for( ; Misc::CharToDigit(*source, base) != -1 ; ++source );
|
for( ; Misc::CharToDigit(*source, conv.base) != -1 ; ++source );
|
||||||
|
|
||||||
return (c==0)? 0 : 1;
|
return (c==0)? 0 : 1;
|
||||||
}
|
}
|
||||||
|
@ -3963,24 +4114,6 @@ private:
|
||||||
public:
|
public:
|
||||||
|
|
||||||
|
|
||||||
/*!
|
|
||||||
a method for converting a string into its value
|
|
||||||
*/
|
|
||||||
uint FromString(const std::string & string, uint base = 10)
|
|
||||||
{
|
|
||||||
return FromString( string.c_str(), base );
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*!
|
|
||||||
a method for converting a string into its value
|
|
||||||
*/
|
|
||||||
uint FromString(const std::wstring & string, uint base = 10)
|
|
||||||
{
|
|
||||||
return FromString( string.c_str(), base );
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
a constructor for converting a string into this class
|
a constructor for converting a string into this class
|
||||||
*/
|
*/
|
||||||
|
@ -4564,8 +4697,7 @@ private:
|
||||||
// we're reading only digits (base=10) and only one comma operator
|
// we're reading only digits (base=10) and only one comma operator
|
||||||
for( ; s.good() ; z=static_cast<char_type>(s.get()) )
|
for( ; s.good() ; z=static_cast<char_type>(s.get()) )
|
||||||
{
|
{
|
||||||
if( z == TTMATH_COMMA_CHARACTER_1 ||
|
if( z=='.' || z==',' )
|
||||||
( z == TTMATH_COMMA_CHARACTER_2 && TTMATH_COMMA_CHARACTER_2 != 0 ) )
|
|
||||||
{
|
{
|
||||||
if( was_comma || was_e )
|
if( was_comma || was_e )
|
||||||
// second comma operator or comma operator after 'e' character
|
// second comma operator or comma operator after 'e' character
|
||||||
|
|
|
@ -110,8 +110,7 @@ namespace ttmath
|
||||||
for example a correct input string can be:
|
for example a correct input string can be:
|
||||||
"1"
|
"1"
|
||||||
"2.1234"
|
"2.1234"
|
||||||
"2,1234" (they are the same, we can either use a comma or a dot in values)
|
"2,1234" (they are the same, by default we can either use a comma or a dot)
|
||||||
(look at the macro TTMATH_COMMA_CHARACTER_2)
|
|
||||||
"1 + 2"
|
"1 + 2"
|
||||||
"(1 + 2) * 3"
|
"(1 + 2) * 3"
|
||||||
"pi"
|
"pi"
|
||||||
|
@ -438,6 +437,28 @@ CGamma<ValueType> cgamma;
|
||||||
std::string wide_to_ansi;
|
std::string wide_to_ansi;
|
||||||
|
|
||||||
|
|
||||||
|
/*!
|
||||||
|
group character (used when parsing)
|
||||||
|
default zero (not used)
|
||||||
|
*/
|
||||||
|
int group;
|
||||||
|
|
||||||
|
|
||||||
|
/*!
|
||||||
|
characters used as a comma
|
||||||
|
default: '.' and ','
|
||||||
|
comma2 can be zero (it means it is not used)
|
||||||
|
*/
|
||||||
|
int comma, comma2;
|
||||||
|
|
||||||
|
|
||||||
|
/*!
|
||||||
|
an additional character used as a separator between function parameters
|
||||||
|
(semicolon is used always)
|
||||||
|
*/
|
||||||
|
int param_sep;
|
||||||
|
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
true if something was calculated (at least one mathematical operator was used or a function or a variable)
|
true if something was calculated (at least one mathematical operator was used or a function or a variable)
|
||||||
*/
|
*/
|
||||||
|
@ -1713,9 +1734,15 @@ void ReadValue(Item & result, int reading_base)
|
||||||
{
|
{
|
||||||
const char * new_stack_pointer;
|
const char * new_stack_pointer;
|
||||||
bool value_read;
|
bool value_read;
|
||||||
|
Conv conv;
|
||||||
|
|
||||||
uint carry = result.value.FromString(pstring, reading_base, &new_stack_pointer, &value_read);
|
conv.base = base;
|
||||||
pstring = new_stack_pointer;
|
conv.comma = comma;
|
||||||
|
conv.comma2 = comma2;
|
||||||
|
conv.group = group;
|
||||||
|
|
||||||
|
uint carry = result.value.FromString(pstring, conv, &new_stack_pointer, &value_read);
|
||||||
|
pstring = new_stack_pointer;
|
||||||
|
|
||||||
if( carry )
|
if( carry )
|
||||||
Error( err_overflow );
|
Error( err_overflow );
|
||||||
|
@ -1730,10 +1757,10 @@ bool value_read;
|
||||||
*/
|
*/
|
||||||
bool ValueStarts(int character, int base)
|
bool ValueStarts(int character, int base)
|
||||||
{
|
{
|
||||||
if( character == TTMATH_COMMA_CHARACTER_1 )
|
if( character == comma )
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
if( TTMATH_COMMA_CHARACTER_2 != 0 && character == TTMATH_COMMA_CHARACTER_2 )
|
if( comma2!=0 && character==comma2 )
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
if( Misc::CharToDigit(character, base) != -1 )
|
if( Misc::CharToDigit(character, base) != -1 )
|
||||||
|
@ -1989,7 +2016,7 @@ int ReadOperator(Item & result)
|
||||||
++pstring;
|
++pstring;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
if( *pstring == ';' )
|
if( *pstring == ';' || (param_sep!=0 && *pstring==param_sep) )
|
||||||
{
|
{
|
||||||
result.type = Item::semicolon;
|
result.type = Item::semicolon;
|
||||||
++pstring;
|
++pstring;
|
||||||
|
@ -2464,12 +2491,16 @@ public:
|
||||||
Parser(): default_stack_size(100)
|
Parser(): default_stack_size(100)
|
||||||
{
|
{
|
||||||
pstop_calculating = 0;
|
pstop_calculating = 0;
|
||||||
puser_variables = 0;
|
puser_variables = 0;
|
||||||
puser_functions = 0;
|
puser_functions = 0;
|
||||||
pfunction_local_variables = 0;
|
pfunction_local_variables = 0;
|
||||||
base = 10;
|
base = 10;
|
||||||
deg_rad_grad = 1;
|
deg_rad_grad = 1;
|
||||||
error = err_ok;
|
error = err_ok;
|
||||||
|
group = 0;
|
||||||
|
comma = '.';
|
||||||
|
comma2 = ',';
|
||||||
|
param_sep = 0;
|
||||||
|
|
||||||
CreateFunctionsTable();
|
CreateFunctionsTable();
|
||||||
CreateVariablesTable();
|
CreateVariablesTable();
|
||||||
|
@ -2488,7 +2519,11 @@ Parser<ValueType> & operator=(const Parser<ValueType> & p)
|
||||||
pfunction_local_variables = 0;
|
pfunction_local_variables = 0;
|
||||||
base = p.base;
|
base = p.base;
|
||||||
deg_rad_grad = p.deg_rad_grad;
|
deg_rad_grad = p.deg_rad_grad;
|
||||||
error = err_ok;
|
error = p.error;
|
||||||
|
group = p.group;
|
||||||
|
comma = p.comma;
|
||||||
|
comma2 = p.comma2;
|
||||||
|
param_sep = p.param_sep;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
we don't have to call 'CreateFunctionsTable()' etc.
|
we don't have to call 'CreateFunctionsTable()' etc.
|
||||||
|
@ -2515,7 +2550,8 @@ Parser(const Parser<ValueType> & p): default_stack_size(p.default_stack_size)
|
||||||
|
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
the new base of mathematic system
|
the new base of mathematic system
|
||||||
|
default is 10
|
||||||
*/
|
*/
|
||||||
void SetBase(int b)
|
void SetBase(int b)
|
||||||
{
|
{
|
||||||
|
@ -2570,6 +2606,39 @@ void SetFunctions(const Objects * pf)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*!
|
||||||
|
setting the group character
|
||||||
|
default zero (not used)
|
||||||
|
*/
|
||||||
|
void SetGroup(int g)
|
||||||
|
{
|
||||||
|
group = g;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*!
|
||||||
|
setting the main comma operator and the additional comma operator
|
||||||
|
the additional operator can be zero (which means it is not used)
|
||||||
|
default are: '.' and ','
|
||||||
|
*/
|
||||||
|
void SetComma(int c, int c2 = 0)
|
||||||
|
{
|
||||||
|
comma = c;
|
||||||
|
comma2 = c2;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*!
|
||||||
|
setting an additional character which is used as a parameters separator
|
||||||
|
the main parameters separator is a semicolon (is used always)
|
||||||
|
|
||||||
|
this character is used also as a global separator
|
||||||
|
*/
|
||||||
|
void SetParamSep(int s)
|
||||||
|
{
|
||||||
|
param_sep = s;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
the main method using for parsing string
|
the main method using for parsing string
|
||||||
|
|
|
@ -233,23 +233,6 @@ namespace ttmath
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/*!
|
|
||||||
characters which represent the comma operator
|
|
||||||
|
|
||||||
TTMATH_COMMA_CHARACTER_1 is used in reading (parsing) and in writing (default, can be overwritten in ToString() function)
|
|
||||||
TTMATH_COMMA_CHARACTER_2 can be used in reading as an auxiliary comma character
|
|
||||||
that means you can input values for example 1.2345 and 1,2345 as well
|
|
||||||
|
|
||||||
if you don't want it just put 0 there e.g.
|
|
||||||
#define TTMATH_COMMA_CHARACTER_2 0
|
|
||||||
then only TTMATH_COMMA_CHARACTER_1 will be used
|
|
||||||
|
|
||||||
don't put there any special character which is used by the parser
|
|
||||||
(for example a semicolon ';' shouldn't be there)
|
|
||||||
*/
|
|
||||||
#define TTMATH_COMMA_CHARACTER_1 '.'
|
|
||||||
#define TTMATH_COMMA_CHARACTER_2 ','
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
|
@ -336,6 +319,114 @@ namespace ttmath
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/*!
|
||||||
|
this struct is used when converting to/from a string
|
||||||
|
*/
|
||||||
|
struct Conv
|
||||||
|
{
|
||||||
|
/*!
|
||||||
|
base (radix) on which the value will be shown (or read)
|
||||||
|
default: 10
|
||||||
|
*/
|
||||||
|
uint base;
|
||||||
|
|
||||||
|
|
||||||
|
/*!
|
||||||
|
used only in Big::ToString()
|
||||||
|
if true the value will be always shown in the scientific mode, e.g: 123e+30
|
||||||
|
default: false
|
||||||
|
*/
|
||||||
|
bool scient;
|
||||||
|
|
||||||
|
|
||||||
|
/*!
|
||||||
|
used only in Big::ToString()
|
||||||
|
if scient is false then the value will be print in the scientific mode
|
||||||
|
only if the exponent is greater than scien_from
|
||||||
|
default: 15
|
||||||
|
*/
|
||||||
|
sint scient_from;
|
||||||
|
|
||||||
|
|
||||||
|
/*!
|
||||||
|
used only in Big::ToString()
|
||||||
|
tells how many digits after comma are possible
|
||||||
|
default: -1 which means all digits are printed
|
||||||
|
|
||||||
|
set it to zero if you want integer value only
|
||||||
|
|
||||||
|
for example when the value is:
|
||||||
|
12.345678 and comma_digit is 4
|
||||||
|
then the result will be
|
||||||
|
12.3457 (the last digit was rounded)
|
||||||
|
*/
|
||||||
|
sint comma_digits;
|
||||||
|
|
||||||
|
|
||||||
|
/*!
|
||||||
|
if true that not mattered digits in the mantissa will be cut off
|
||||||
|
(zero characters at the end -- after the comma operator)
|
||||||
|
e.g. 1234,78000 will be: 1234,78
|
||||||
|
default: true
|
||||||
|
*/
|
||||||
|
bool trim_zeroes;
|
||||||
|
|
||||||
|
|
||||||
|
/*!
|
||||||
|
the main comma operator (used when reading and writing)
|
||||||
|
default is a dot '.'
|
||||||
|
*/
|
||||||
|
uint comma;
|
||||||
|
|
||||||
|
|
||||||
|
/*!
|
||||||
|
additional comma operator (used only when reading)
|
||||||
|
if you don't want it just set it to zero
|
||||||
|
default is a comma ','
|
||||||
|
|
||||||
|
this allowes you to convert from a value:
|
||||||
|
123.45 as well as from 123,45
|
||||||
|
*/
|
||||||
|
uint comma2;
|
||||||
|
|
||||||
|
|
||||||
|
/*!
|
||||||
|
it sets the character which is used for grouping
|
||||||
|
if group=' ' then: 1234,56789 will be printed as: 1 234,567 89
|
||||||
|
|
||||||
|
if you don't want grouping just set it to zero (which is default)
|
||||||
|
*/
|
||||||
|
uint group;
|
||||||
|
|
||||||
|
|
||||||
|
/*!
|
||||||
|
*/
|
||||||
|
uint group_exp; // not implemented yet
|
||||||
|
|
||||||
|
|
||||||
|
/*!
|
||||||
|
*/
|
||||||
|
bool group_multiple; // not implemented yet
|
||||||
|
|
||||||
|
|
||||||
|
Conv()
|
||||||
|
{
|
||||||
|
// default values
|
||||||
|
base = 10;
|
||||||
|
scient = false;
|
||||||
|
scient_from = 15;
|
||||||
|
comma_digits = -1; // !! change to 'round' ?
|
||||||
|
trim_zeroes = true;
|
||||||
|
comma = '.';
|
||||||
|
comma2 = ',';
|
||||||
|
group = 0;
|
||||||
|
group_exp = 0;
|
||||||
|
group_multiple = true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
this simple class can be used in multithreading model
|
this simple class can be used in multithreading model
|
||||||
(you can write your own class derived from this one)
|
(you can write your own class derived from this one)
|
||||||
|
|
Loading…
Reference in New Issue