public void ConvertFloats() { AString a= new AString(); int pos; int posOrig; // parse on empty a.Clear(); { posOrig= pos= 0; UT_EQ( 0.0, a.ToFloat ( pos ) ); UT_EQ( pos, posOrig ); posOrig= pos= -5; UT_EQ( 0.0, a.ToFloat ( pos ) ); } // parse on non number a.Clear()._( "Hello"); { posOrig= pos= 0; UT_EQ( 0.0, a.ToFloat ( pos ) ); posOrig= pos= -5; UT_EQ( 0.0, a.ToFloat ( pos ) ); posOrig= pos= 2; UT_EQ( 0.0, a.ToFloat ( pos ) ); } // check that leading whitespaces do not move pointer a.Clear()._( " Hello"); { posOrig= pos= 0; UT_EQ( 0.0, a.ToFloat ( pos ) ); posOrig= pos= -5; UT_EQ( 0.0, a.ToFloat ( pos ) ); posOrig= pos= 2; UT_EQ( 0.0, a.ToFloat ( pos ) ); } // parse floats { NumberFormat nf= new NumberFormat(); a.Clear()._( "12345.789"); UT_EQ( 12345.789, a.ToFloat( 0, out pos, nf ) ); UT_EQ( 0 + a.Length() , pos ); a.Clear()._( ""); UT_EQ( 0.0, a.ToFloat( 0, out pos, nf ) ); UT_EQ( 0 , pos ); a.Clear()._( "-"); UT_EQ( 0.0, a.ToFloat( 0, out pos, nf ) ); UT_EQ( 0 , pos ); a.Clear()._( "-X"); UT_EQ( 0.0, a.ToFloat( 0, out pos, nf ) ); UT_EQ( 0 , pos ); a.Clear()._( "."); UT_EQ( 0.0, a.ToFloat( 0, out pos, nf ) ); UT_EQ( 1 , pos ); a.Clear()._( ".0"); UT_EQ( 0.0, a.ToFloat( 0, out pos, nf ) ); UT_EQ( 2 , pos ); a.Clear()._( "0."); UT_EQ( 0.0, a.ToFloat( 0, out pos, nf ) ); UT_EQ( 2 , pos ); a.Clear()._( ".5"); UT_EQ( 0.5, a.ToFloat( 0, out pos, nf ) ); UT_EQ( 2 , pos ); a.Clear()._( "5."); UT_EQ( 5.0, a.ToFloat( 0, out pos, nf ) ); UT_EQ( 2 , pos ); a.Clear()._( "+0"); UT_EQ( 0.0, a.ToFloat( 0, out pos, nf ) ); UT_EQ( 2 , pos ); a.Clear()._( "-0"); UT_EQ( 0.0, a.ToFloat( 0, out pos, nf ) ); UT_EQ( 2 , pos ); a.Clear()._( "+6"); UT_EQ( 6.0, a.ToFloat( 0, out pos, nf ) ); UT_EQ( 2 , pos ); a.Clear()._( "-7"); UT_EQ( -7.0, a.ToFloat( 0, out pos, nf ) ); UT_EQ( 2 , pos ); a.Clear()._( "-7"); UT_EQ( 7.0, a.ToFloat( 1, out pos, nf ) ); UT_EQ( 2 , pos ); a.Clear()._( "+42"); UT_EQ( 42.0, a.ToFloat( 0, out pos, nf ) ); UT_EQ( 3 , pos ); a.Clear()._( " -42 "); UT_EQ(-42.0, a.ToFloat( 0, out pos, nf ) ); UT_EQ( 4 , pos ); a.Clear()._( " +42. "); UT_EQ( 42.0, a.ToFloat( 0, out pos, nf ) ); UT_EQ( 6 , pos ); a.Clear()._( " 123"); UT_EQ( 123.0, a.ToFloat( 0, out pos, nf ) ); UT_EQ( 0 + a.Length() , pos ); a.Clear()._( " -23 "); UT_EQ( -23.0, a.ToFloat( 0, out pos, nf ) ); UT_EQ( 5 , pos ); a.Clear()._( "123 "); UT_EQ( 123.0, a.ToFloat( 0, out pos, nf ) ); UT_EQ( 3 , pos ); a.Clear()._( "xxx123456789"); UT_EQ( 123456789.0, a.ToFloat( 3, out pos, nf ) ); UT_EQ( 0 + a.Length() , pos ); a.Clear()._( "xxx 1.3"); UT_EQ( 1.3, a.ToFloat( 3, out pos, nf ) ); UT_EQ( 0 + a.Length() , pos ); a.Clear()._( "xxx 1.3 "); UT_EQ( 1.3, a.ToFloat( 3, out pos, nf ) ); UT_EQ( 0 + a.Length()-2 , pos ); a.Clear()._( "xxx1.3 "); UT_EQ( 1.3, a.ToFloat( 3, out pos, nf ) ); UT_EQ( 0 + a.Length()-2 , pos ); nf.DecimalPointCharacters= "@".ToCharArray(); a.Clear()._( "-2495@321"); UT_EQ( -2495.321, a.ToFloat( 0, out pos, nf ) ); UT_EQ( 0 + a.Length() , pos ); } // write floats, non scientific mode { // digits after dot: -1 floatTest( 3.0 ,'.' , -1, -1 , "3.0" ); floatTest( 3.1 ,'.' , -1, -1 , "3.1" ); floatTest( 3.14 ,'.' , -1, -1 , "3.14" ); floatTest( 3.145 ,'.' , -1, -1 , "3.145" ); floatTest( 3.02 ,'.' , -1, -1 , "3.02" ); floatTest( 3.001 ,'.' , -1, -1 , "3.001" ); floatTest( 3.09 ,'.' , -1, -1 , "3.09" ); floatTest( 3.009 ,'.' , -1, -1 , "3.009" ); floatTest( 0.0 ,'.' , -1, -1 , "0.0" ); floatTest( 0.1 ,'.' , -1, -1 , "0.1" ); floatTest( 0.14 ,'.' , -1, -1 , "0.14" ); floatTest( 0.145 ,'.' , -1, -1 , "0.145" ); floatTest( 0.02 ,'.' , -1, -1 , "0.02" ); floatTest( 0.001 ,'.' , -1, -1 , "0.001" ); floatTest( 0.09 ,'.' , -1, -1 , "0.09" ); floatTest( 0.009 ,'.' , -1, -1 , "0.009" ); // forces scientific notation floatTest( 3.0 ,'.' , -1, -1 , "3.0E00" , true ); floatTest( 3.1 ,'.' , -1, -1 , "3.1E00" , true ); floatTest( 3.14 ,'.' , -1, -1 , "3.14E00" , true ); floatTest( 3.145 ,'.' , -1, -1 , "3.145E00" , true ); floatTest( 3.02 ,'.' , -1, -1 , "3.02E00" , true ); floatTest( 3.001 ,'.' , -1, -1 , "3.001E00" , true ); floatTest( 3.09 ,'.' , -1, -1 , "3.09E00" , true ); floatTest( 3.009 ,'.' , -1, -1 , "3.009E00" , true ); floatTest( 3.145 ,'.' , -1, 1 , "3.1E00" , true ); floatTest( 3.145 ,'.' , 1, 1 , "3.1E00" , true ); floatTest( 3.145 ,'.' , 5, 3 , "00003.145E00" , true ); floatTest( 123.12341234 ,'.' , -1, 6 , "1.231234E02" , true ); floatTest( 0.00123123123 ,'.' , -1, 6 , "1.231231E-03" , true ); floatTest( 0.321 ,'.' , 0, 6 , "3.210000E-01" , true ); floatTest( 3.789 ,'.' , -1, 1 , "3.8E00" , true ); floatTest( 123.78978978 ,'.' , -1, 6 , "1.237898E02" , true ); floatTest( 0.00789789789 ,'.' , -1, 6 , "7.897898E-03" , true ); // many digits after dot // 123456789 123456789 12345 double RoundDown= 1.123412341234123412341234; floatTest( RoundDown ,'.' , 1, 12 , "1.123412341234" ); floatTest( RoundDown ,'.' , 1, 13 , "1.1234123412341" ); floatTest( RoundDown ,'.' , 1, 14 , "1.12341234123412" ); floatTest( RoundDown ,'.' , 1, 15 , "1.123412341234123" ); RoundDown= 0.123412341234123412341234; floatTest( RoundDown ,'.' , 1, 12 , "0.123412341234" ); floatTest( RoundDown ,'.' , 1, 13 , "0.1234123412341" ); floatTest( RoundDown ,'.' , 1, 14 , "0.12341234123412" ); floatTest( RoundDown ,'.' , 1, 15 , "0.123412341234123" ); double RoundUp= 1.678967896789678967896789; floatTest( RoundUp ,'.' , 1, 12 , "1.678967896790" ); floatTest( RoundUp ,'.' , 1, 13 , "1.6789678967897" ); floatTest( RoundUp ,'.' , 1, 14 , "1.67896789678968" ); floatTest( RoundUp ,'.' , 1, 15 , "1.678967896789679" ); RoundUp= 0.678967896789678967896789; floatTest( RoundUp ,'.' , 1, 12 , "0.678967896790" ); floatTest( RoundUp ,'.' , 1, 13 , "0.6789678967897" ); floatTest( RoundUp ,'.' , 1, 14 , "0.67896789678968" ); floatTest( RoundUp ,'.' , 1, 15 , "0.678967896789679" ); // 123456789 123456789 123456789 12345 floatTest( 0.00001234123412341234 ,'.' , 1, 15 , "0.000012341234123" ); floatTest( 0.00000123412341234123 ,'.' , 1, 15 , "0.000001234123412" ); floatTest( 0.00000012341234123412 ,'.' , 1, 15 , "0.000000123412341" ); floatTest( 0.00000001234123412341 ,'.' , 1, 15 , "0.000000012341234" ); floatTest( 0.00000000123412341234 ,'.' , 1, 15 , "0.000000001234123" ); floatTest( 0.00000000012341234123 ,'.' , 1, 15 , "0.000000000123412" ); floatTest( 0.00000000001234123412 ,'.' , 1, 15 , "0.000000000012341" ); floatTest( 0.00000000000123412341 ,'.' , 1, 15 , "0.000000000001234" ); floatTest( 0.00000000000012341234 ,'.' , 1, 15 , "0.000000000000123" ); floatTest( 0.00000000000001234123 ,'.' , 1, 15 , "0.000000000000012" ); floatTest( 0.00000000000000123412 ,'.' , 1, 15 , "0.000000000000001" ); floatTest( 0.00000000000000012341 ,'.' , 1, 15 , "0.000000000000000" ); floatTest( 0.00000000000000001234 ,'.' , 1, 15 , "0.000000000000000" ); floatTest( 0.00006789678967896789 ,'.' , 1, 15 , "0.000067896789679" ); floatTest( 0.00000678967896789678 ,'.' , 1, 15 , "0.000006789678968" ); floatTest( 0.00000067896789678967 ,'.' , 1, 15 , "0.000000678967897" ); floatTest( 0.00000006789678967896 ,'.' , 1, 15 , "0.000000067896790" ); floatTest( 0.00000000678967896789 ,'.' , 1, 15 , "0.000000006789679" ); floatTest( 0.00000000067896789678 ,'.' , 1, 15 , "0.000000000678968" ); floatTest( 0.00000000006789678967 ,'.' , 1, 15 , "0.000000000067897" ); floatTest( 0.00000000000678967896 ,'.' , 1, 15 , "0.000000000006790" ); floatTest( 0.00000000000067896789 ,'.' , 1, 15 , "0.000000000000679" ); floatTest( 0.00000000000006789678 ,'.' , 1, 15 , "0.000000000000068" ); floatTest( 0.00000000000000678967 ,'.' , 1, 15 , "0.000000000000007" ); floatTest( 0.00000000000000067896 ,'.' , 1, 15 , "0.000000000000001" ); floatTest( 0.00000000000000006789 ,'.' , 1, 15 , "0.000000000000000" ); floatTest( 0.00000000000000000678 ,'.' , 1, 15 , "0.000000000000000" ); // digits after dot: 0 or positive floatTest( 300.00050000001 ,'.' , 1, 2 , "300.00" ); floatTest( 300.00050000001 ,'.' , 1, 3 , "300.001" ); floatTest( 300.00050000001 ,'.' , 1, 4 , "300.0005" ); floatTest( 300.00050000001 ,'.' , 1, 5 , "300.00050" ); floatTest( 300.00050000001 ,'.' , 1, 6 , "300.000500" ); floatTest( 5.01 ,'.' , 1, 3 , "5.010" ); floatTest( 0.5 ,'.' , 0, 0 , "." ); floatTest( 0.5 ,'.' , 0, 1 , ".5" ); floatTest( 0.5 ,'.' , 1, 0 , "0." ); floatTest( 0.5 ,'.' , 1, 1 , "0.5" ); floatTest( 0.5 ,'.' , 2, 2 , "00.50" ); floatTest( 0.5 ,'.' , 3, 3 , "000.500" ); floatTest( 0.54 ,'.' , 3, 3 , "000.540" ); floatTest( 0.543 ,'.' , 3, 3 , "000.543" ); floatTest( 0.5432 ,'.' , 3, 3 , "000.543" ); floatTest( 23.37 ,'.' , 2, 1 , "23.4" ); floatTest( 1.5 ,'.' , 0, 0 , "1." ); floatTest( 1.9 ,'.' , 0, 0 , "2." ); floatTest( 1.9 ,'.' , 0, 4 , "1.9000" ); floatTest( 1.500001 ,'.' , 0, 0 , "2." ); floatTest( 1.54 ,'.' , 3, 3 , "001.540" ); floatTest( 1.543 ,'.' , 3, 3 , "001.543" ); floatTest( 1.5432 ,'.' , 3, 3 , "001.543" ); floatTest( 23.37 ,'.' , 2, 3 , "23.370" ); floatTest( 12.345 ,'.' , 0, 3 , "12.345" ); floatTest( 12.345 ,'.' , 5, 1 , "00012.3" ); floatTest( 12.36789 ,'.' , 5, 1 , "00012.4" ); floatTest( 1.5 ,'.' , 0, 0 , "1." ); floatTest( 1.5 ,'.' , 1, 0 , "1." ); floatTest( 1.5 ,'.' , 0, 1 , "1.5" ); floatTest( 1.5 ,'.' , 1, 1 , "1.5" ); floatTest( 1.5 ,'.' , 2, 2 , "01.50" ); floatTest( 1.5 ,'.' , 3, 3 , "001.500" ); floatTest( 1.54 ,'.' , 3, 3 , "001.540" ); floatTest( 1.543 ,'.' , 3, 3 , "001.543" ); floatTest( 1.5432 ,'.' , 3, 3 , "001.543" ); floatTest( 0.0 ,'.' , 0, 0 , "." ); floatTest( 0.0 ,'.' , 1, 0 , "0." ); floatTest( 0.0 ,'.' , 0, 1 , ".0" ); floatTest( 0.0 ,'.' , 1, 1 , "0.0" ); floatTest( 0.0 ,'.' , 2, 2 , "00.00" ); floatTest( 10.0 ,'.' , 2, 2 , "10.00" ); floatTest( 23.37 ,'.' , 2, 1 , "23.4" ); floatTest( 23.37 ,'.' , 2, 3 , "23.370" ); floatTest( 12.345 ,'.' , 0, 3 , "12.345" ); floatTest( - 5.1 ,'.' , 5, 0 , "-00005." ); floatTest( - 5.1 ,'.' , 5, 1 , "-00005.1" ); floatTest( - 53.24 ,'.' , 2, 2 , "-53.24" ); floatTest( - 0.2 ,'.' , 1, 3 , "-0.200" ); floatTest( - 0.6 ,'.' , 1, 3 , "-0.600" ); floatTest( - 0.999 ,'.' , 1, 3 , "-0.999" ); floatTest( 0.999 ,'.' , 1, 3 , "0.999" ); floatTest( 0.99 ,'.' , 1, 3 , "0.990" ); floatTest( 0.999 ,'.' , 1, 3 , "0.999" ); floatTest( 0.9999 ,'.' , 1, 3 , "1.000" ); floatTest( 0.0999 ,'.' , 2, 3 , "00.100" ); floatTest( 0.99999 ,'.' , 1, 3 , "1.000" ); floatTest( 0.099 ,'.' , 2, 3 , "00.099" ); floatTest( 0.0999 ,'.' , 1, 3 , "0.100" ); floatTest( 0.09999 ,'.' , 2, 3 , "00.100" ); floatTest( 0.999 ,'.' , 2, 3 , "00.999" ); floatTest( 0.0099 ,'.' , 1, 3 , "0.010" ); floatTest( 0.00999 ,'.' , 1, 3 , "0.010" ); floatTest( 0.009 ,'.' , 1, 3 , "0.009" ); floatTest( 0.00099 ,'.' , 1, 3 , "0.001" ); floatTest( 0.00009 ,'.' , 1, 3 , "0.000" ); floatTest( 1.0099 ,'.' , 1, 3 , "1.010" ); floatTest( 1.00999 ,'.' , 1, 3 , "1.010" ); floatTest( 1.009 ,'.' , 1, 3 , "1.009" ); floatTest( 1.00099 ,'.' , 1, 3 , "1.001" ); floatTest( 1.00009 ,'.' , 1, 3 , "1.000" ); floatTest( 0.00050 ,'.' , 1, 3 , "0.000" ); floatTest( 0.00051 ,'.' , 1, 3 , "0.001" ); floatTest( 0.00050000001 ,'.' , 1, 3 , "0.001" ); floatTest( 300.00050000001 ,'.' , 1, 3 , "300.001" ); floatTest( 0.10099 ,'.' , 1, 4 , "0.1010" ); floatTest( 0.10099 ,'.' , 1, 4 , "0.1010" ); floatTest( 0.00099 ,'.' , 1, 4 , "0.0010" ); floatTest( 1.099 ,'.' , 1, 1 , "1.1" ); floatTest( 0.00999 ,'.' , 1, 4 , "0.0100" ); // roundtrip -3.0 to 3.0 step 0.001 { for (int digits= -1 ; digits < 5 ; digits++ ) { double d= -3.0; double end= 3.0; double inc= 0.001; while ( d <= end ) { floatTest( d, '\0' , -1, digits, null ); d+= inc; } } } // roundtrip e-200 to e+200 { Random r = new Random(); for ( int exp= -200 ; exp <= 200 ; exp+=1 ) { double expFactor= Math.Pow( 10, exp ); for ( int t= 0 ; t <= 1000 ; t++) { // create a random number of type r.rrrrr *10^exp double d= r.NextDouble(); while ( d < 1.0 ) d*= 10.0; d*= expFactor; if ( (t & 1 ) != 0 ) d= -d; floatTest( d, '\0' , -1, -1, null ); } } } // special exponent symbol { int dummy; NumberFormat nf= new NumberFormat(); nf.DecimalExponentSeparator= "*10^".ToCharArray(); AString s= new AString(); double v= 7.5E42; s._( v, nf ); UT_EQ( s, "7.5*10^42" ); double back= s.ToFloat( 0, out dummy, nf ); UT_EQ( v, back, 0.0000000001 ); } } }
//-------------------------------------------------------------------------------------------------- //--- Test ConvertFloats //-------------------------------------------------------------------------------------------------- void floatTest( double d, char decimalPoint, int minDigitsBeforeDot, int digitsAfterDot, String expectedString, bool forceScientific= false ) { AString ms= new AString(); NumberFormat nf= new NumberFormat(); nf.ForceScientificFormat= forceScientific; if ( decimalPoint == '\0' ) { // reset ALIB' number format to reflect current locale NumberFormat.Global.SetFromLocale(); nf.DecimalPointCharacter= NumberFormat.Global.DecimalPointCharacter; } else nf.DecimalPointCharacter= decimalPoint; nf.MinIntegralDigits= minDigitsBeforeDot; nf.FractionalDigits= digitsAfterDot; ms._( d, nf ); if ( expectedString != null ) { UT_EQ( expectedString, ms ); } double precision= digitsAfterDot < 0 ? Math.Pow( 10, (d != 0.0 ? (int) Math.Floor((Math.Log10( d ) )) : 0 ) - 14 ) : Math.Pow( 10, digitsAfterDot ) / 2.0; // check with system parsing (only if system specific decimal point format was given) if ( decimalPoint == '\0' ) { double dSystem= 0.0; try { dSystem= Double.Parse( ms.ToString(), CultureInfo.CurrentCulture ); } catch( Exception ) { UT_TRUE( digitsAfterDot == 0 ); // this is not really allowed in c# when parsing dSystem= d; } UT_EQ( d, dSystem, precision ); } // check with aworx parsing double dAWorx= ms.ToFloat(); UT_EQ( d, dAWorx, precision ); }