@@ -52,19 +52,23 @@ public FInt Decimal
5252 }
5353
5454 /// <summary>
55- /// Gets the sign of the number.
55+ /// Returns an integer that indicates the sign of the number.
5656 /// </summary>
57- public FInt Sign
57+ public int Sign
5858 {
5959 get
6060 {
61- if ( _value >= 0 )
61+ if ( _value == 0 )
62+ {
63+ return 0 ;
64+ }
65+ else if ( _value > 0 )
6266 {
63- return 1 . FI ( ) ;
67+ return 1 ;
6468 }
6569 else
6670 {
67- return ( - 1 ) . FI ( ) ;
71+ return - 1 ;
6872 }
6973 }
7074 }
@@ -110,18 +114,23 @@ public FInt(long value)
110114 }
111115
112116 /// <summary>
113- /// Initializes a new instance of <see cref="FInt"/> from two <see cref="int"/> values .
117+ /// Initializes a new instance of <see cref="FInt"/> from two parts: the integer and the decimal .
114118 /// </summary>
115- /// <param name="integerValue ">The integer portion of the number.</param>
116- /// <param name="decimalValue">The decimal portion of the number.</param>
117- /// <param name="numDecimalDigits">The number of digits in <paramref name="decimalValue"/>.</param>
119+ /// <param name="integralValue ">The integer portion of the number. Can't be negative .</param>
120+ /// <param name="decimalValue">The decimal portion of the number. Can't be negative. </param>
121+ /// <param name="numDecimalDigits">The number of digits in <paramref name="decimalValue"/>. Must be between 1 and <see cref="PRECISION"/>. </param>
118122 /// <exception cref="ArgumentException"></exception>
119123 /// <exception cref="ArgumentOutOfRangeException"></exception>
120- public FInt ( int integerValue , int decimalValue , int numDecimalDigits )
124+ public FInt ( int integralValue , int decimalValue , int numDecimalDigits )
121125 {
122- if ( decimalValue < 0 )
126+ if ( integralValue < 0 )
127+ {
128+ throw new ArgumentOutOfRangeException ( $ "Integral value cannot be negative.", nameof ( integralValue ) ) ;
129+ }
130+
131+ if ( decimalValue < 0 )
123132 {
124- throw new ArgumentException ( $ "Decimal value can't be negative.", nameof ( decimalValue ) ) ;
133+ throw new ArgumentOutOfRangeException ( $ "Decimal value can't be negative.", nameof ( decimalValue ) ) ;
125134 }
126135
127136 //get the scale multiplier based on input
@@ -145,17 +154,67 @@ public FInt(int integerValue, int decimalValue, int numDecimalDigits)
145154 }
146155
147156 //assign the scaled integer value
148- _value = integerValue * _SCALE ;
157+ _value = integralValue * _SCALE ;
149158
150- //if the integer portion is negative
151- if ( integerValue < 0 )
159+ //add the decimal
160+ _value += scaledDecimal ;
161+ }
162+
163+ /// <summary>
164+ /// Initializes a new instance of <see cref="FInt"/> from two parts: the integer and the decimal.
165+ /// </summary>
166+ /// <param name="integralValue">The integer portion of the number. Can't be negative.</param>
167+ /// <param name="decimalValue">The decimal portion of the number. Can't be negative.</param>
168+ /// <param name="numDecimalDigits">The number of digits in <paramref name="decimalValue"/>. Must be between 1 and <see cref="PRECISION"/>.</param>
169+ /// <exception cref="ArgumentException"></exception>
170+ /// <exception cref="ArgumentOutOfRangeException"></exception>
171+ /// <exception cref="OverflowException"></exception>
172+ public FInt ( long integralValue , int decimalValue , int numDecimalDigits )
173+ {
174+ if ( integralValue < 0 )
152175 {
153- //subtract the decimal portion
154- _value -= scaledDecimal ;
155- return ;
176+ throw new ArgumentOutOfRangeException ( $ "Integral value cannot be negative.", nameof ( integralValue ) ) ;
177+ }
178+
179+ if ( decimalValue < 0 )
180+ {
181+ throw new ArgumentOutOfRangeException ( $ "Decimal value cannot be negative.", nameof ( decimalValue ) ) ;
182+ }
183+
184+ if ( integralValue > long . MaxValue / _SCALE )
185+ {
186+ throw new OverflowException ( "Overflow caused by scaling integral value." ) ;
187+ }
188+
189+ //get the scale multiplier based on input
190+ int decimalScale = numDecimalDigits switch
191+ {
192+ 1 => 100_000 ,
193+ 2 => 10_000 ,
194+ 3 => 1_000 ,
195+ 4 => 100 ,
196+ 5 => 10 ,
197+ 6 => 1 ,
198+ _ => throw new ArgumentOutOfRangeException ( nameof ( numDecimalDigits ) , $ "Decimal digits must be between 1 and { PRECISION } .")
199+ } ;
200+
201+ //scale the decimal up to the correct value
202+ long scaledDecimal = decimalValue * decimalScale ;
203+
204+ if ( scaledDecimal >= _SCALE )
205+ {
206+ throw new ArgumentException ( $ "Scaled decimal value '{ scaledDecimal } ' cannot exceed '{ _SCALE } '. Check { nameof ( decimalValue ) } and { nameof ( numDecimalDigits ) } .") ;
207+ }
208+
209+ //assign the scaled integer value
210+ _value = integralValue * _SCALE ;
211+
212+ if ( long . MaxValue - _value < scaledDecimal )
213+ {
214+ throw new OverflowException ( $ "Max value is '{ MaxValue } '.") ;
156215 }
157216
158- //integer is positive so add the decimal
217+ //add the decimal
159218 _value += scaledDecimal ;
160219 }
161220
@@ -489,7 +548,64 @@ public static implicit operator FInt(long value)
489548 /// <returns></returns>
490549 public static FInt Parse ( string s )
491550 {
492- return new FInt ( long . Parse ( s ) ) ;
551+ int decimalPointIndex = s . IndexOf ( '.' ) ;
552+
553+ if ( decimalPointIndex == - 1 )
554+ {
555+ return long . Parse ( s ) ;
556+ }
557+
558+ string integralString = s . Substring ( 0 , decimalPointIndex ) ;
559+
560+ //don't take more digits that we can handle
561+ int decimalStringLength = int . Min ( s . Length - ( decimalPointIndex + 1 ) , PRECISION ) ;
562+ string decimalString = s . Substring ( decimalPointIndex + 1 , decimalStringLength ) ;
563+
564+ long integralValue = 0 ;
565+ int decimalValue = 0 ;
566+
567+ int sign = 1 ;
568+
569+ if ( integralString . Length > 0 )
570+ {
571+ if ( integralString == "-" )
572+ {
573+ sign = - 1 ;
574+ }
575+ else
576+ {
577+ if ( integralString [ 0 ] == '-' )
578+ {
579+ sign = - 1 ;
580+
581+ //remove the negative sign
582+ integralString = integralString . Substring ( 1 ) ;
583+ }
584+
585+ integralValue = long . Parse ( integralString ) ;
586+ }
587+ }
588+
589+ if ( decimalString . Length > 0 )
590+ {
591+ if ( decimalString [ 0 ] == '-' )
592+ {
593+ throw new FormatException ( $ "The input string '{ s } ' was not in a correct format.") ;
594+ }
595+
596+ decimalValue = int . Parse ( decimalString ) ;
597+ }
598+
599+ int numDecimalDigits = int . Max ( 1 , decimalString . Length ) ;
600+
601+ FInt result = new FInt ( integralValue , decimalValue , numDecimalDigits ) ;
602+
603+ if ( sign < 0 )
604+ {
605+ result = - result ;
606+ }
607+
608+ return result ;
493609 }
494610
495611 /// <summary>
@@ -778,8 +894,13 @@ private static int _cosLookUp(int deg)
778894
779895public static class FIntQoLExtensions
780896{
781- public static FInt FI ( this int i )
897+ public static FInt FI ( this int value )
782898 {
783- return new FInt ( i ) ;
899+ return value ;
784900 }
901+
902+ public static FInt FI ( this long value )
903+ {
904+ return value ;
905+ }
785906}
0 commit comments