5 // Miguel de Icaza (miguel@ximian.com)
6 // Bob Smith (bob@thestuff.net)
8 // (C) Ximian, Inc. http://www.ximian.com
9 // (C) Bob Smith. http://www.thestuff.net
12 using System.Globalization;
13 using System.Runtime.CompilerServices;
18 public struct Double : IComparable, IFormattable, IConvertible {
19 public const double Epsilon = 4.9406564584124650e-324;
20 public const double MaxValue = 1.7976931348623157e308;
21 public const double MinValue = -1.7976931348623157e308;
22 public const double NaN = 0.0d / 0.0d;
23 public const double NegativeInfinity = -1.0d / 0.0d;
24 public const double PositiveInfinity = 1.0d / 0.0d;
26 internal double value;
28 public int CompareTo (object v)
33 if (!(v is System.Double))
34 throw new ArgumentException (Locale.GetText ("Value is not a System.Double"));
36 double dv = (double)v;
38 if (IsPositiveInfinity(value) && IsPositiveInfinity(dv))
41 if (IsNegativeInfinity(value) && IsNegativeInfinity(dv))
56 if (value > dv) return 1;
57 else if (value < dv) return -1;
61 public override bool Equals (object o)
63 if (!(o is System.Double))
66 if (IsNaN ((double)o)) {
73 return ((double) o) == value;
76 public override int GetHashCode ()
81 public static bool IsInfinity (double d)
83 return (d == PositiveInfinity || d == NegativeInfinity);
86 public static bool IsNaN (double d)
91 public static bool IsNegativeInfinity (double d)
93 return (d < 0.0d && (d == NegativeInfinity || d == PositiveInfinity));
96 public static bool IsPositiveInfinity (double d)
98 return (d > 0.0d && (d == NegativeInfinity || d == PositiveInfinity));
101 public static double Parse (string s)
103 return Parse (s, (NumberStyles.Float | NumberStyles.AllowThousands), null);
106 public static double Parse (string s, IFormatProvider fp)
108 return Parse (s, (NumberStyles.Float | NumberStyles.AllowThousands), fp);
111 public static double Parse (string s, NumberStyles style)
113 return Parse (s, style, null);
116 // We're intentionally using constants here to avoid some bigger headaches in mcs.
117 // This struct must be compiled before System.Enum so we can't use enums here.
118 private const int State_AllowSign = 1;
119 private const int State_Digits = 2;
120 private const int State_Decimal = 3;
121 private const int State_ExponentSign = 4;
122 private const int State_Exponent = 5;
123 private const int State_ConsumeWhiteSpace = 6;
125 [MonoTODO("check if digits are group in correct numbers between the group separators")]
126 public static double Parse (string s, NumberStyles style, IFormatProvider provider)
128 if (s == null) throw new ArgumentNullException();
129 if (style > NumberStyles.Any)
131 throw new ArgumentException();
133 NumberFormatInfo format = NumberFormatInfo.GetInstance(provider);
134 if (format == null) throw new Exception("How did this happen?");
135 if (s == format.NaNSymbol) return Double.NaN;
136 if (s == format.PositiveInfinitySymbol) return Double.PositiveInfinity;
137 if (s == format.NegativeInfinitySymbol) return Double.NegativeInfinity;
140 // validate and prepare string for C
143 byte [] b = new byte [len + 1];
148 if ((style & NumberStyles.AllowLeadingWhite) != 0){
149 while (sidx < len && Char.IsWhiteSpace (c = s [sidx]))
153 throw new FormatException();
156 bool allow_trailing_white = ((style & NumberStyles.AllowTrailingWhite) != 0);
161 int state = State_AllowSign;
166 string decimal_separator = null;
167 string group_separator = null;
168 int decimal_separator_len = 0;
169 int group_separator_len = 0;
170 if ((style & NumberStyles.AllowDecimalPoint) != 0){
171 decimal_separator = format.NumberDecimalSeparator;
172 decimal_separator_len = decimal_separator.Length;
174 if ((style & NumberStyles.AllowThousands) != 0){
175 group_separator = format.NumberGroupSeparator;
176 group_separator_len = group_separator.Length;
178 string positive = format.PositiveSign;
179 string negative = format.NegativeSign;
181 for (; sidx < len; sidx++){
185 case State_AllowSign:
186 if ((style & NumberStyles.AllowLeadingSign) != 0){
187 if (c == positive [0] &&
188 s.Substring (sidx, positive.Length) == positive){
189 state = State_Digits;
190 sidx += positive.Length-1;
194 if (c == negative [0] &&
195 s.Substring (sidx, negative.Length) == negative){
196 state = State_Digits;
197 b [didx++] = (byte) '-';
198 sidx += negative.Length-1;
202 state = State_Digits;
203 goto case State_Digits;
206 if (Char.IsDigit (c)){
207 b [didx++] = (byte) c;
210 if (c == 'e' || c == 'E')
211 goto case State_Decimal;
213 if (decimal_separator != null &&
214 decimal_separator [0] == c){
215 if (s.Substring (sidx, decimal_separator_len) ==
217 b [didx++] = (byte) '.';
218 sidx += decimal_separator_len-1;
219 state = State_Decimal;
223 if (group_separator != null &&
224 group_separator [0] == c){
225 if (s.Substring (sidx, group_separator_len) ==
227 sidx += group_separator_len-1;
228 state = State_Digits;
233 if (Char.IsWhiteSpace (c))
234 goto case State_ConsumeWhiteSpace;
236 throw new FormatException ("Unknown char: " + c);
239 if (Char.IsDigit (c)){
240 b [didx++] = (byte) c;
244 if (c == 'e' || c == 'E'){
245 if ((style & NumberStyles.AllowExponent) == 0)
246 throw new FormatException ("Unknown char: " + c);
247 b [didx++] = (byte) c;
248 state = State_ExponentSign;
252 if (Char.IsWhiteSpace (c))
253 goto case State_ConsumeWhiteSpace;
254 throw new FormatException ("Unknown char: " + c);
256 case State_ExponentSign:
257 if (Char.IsDigit (c)){
258 state = State_Exponent;
259 goto case State_Exponent;
262 if (c == positive [0] &&
263 s.Substring (sidx, positive.Length) == positive){
264 state = State_Digits;
265 sidx += positive.Length-1;
269 if (c == negative [0] &&
270 s.Substring (sidx, negative.Length) == negative){
271 state = State_Digits;
272 b [didx++] = (byte) '-';
273 sidx += negative.Length-1;
277 if (Char.IsWhiteSpace (c))
278 goto case State_ConsumeWhiteSpace;
280 throw new FormatException ("Unknown char: " + c);
283 if (Char.IsDigit (c)){
284 b [didx++] = (byte) c;
288 if (Char.IsWhiteSpace (c))
289 goto case State_ConsumeWhiteSpace;
290 throw new FormatException ("Unknown char: " + c);
292 case State_ConsumeWhiteSpace:
293 if (allow_trailing_white && Char.IsWhiteSpace (c))
295 throw new FormatException ("Unknown char");
301 fixed (byte *p = &b [0]){
302 double retVal = ParseImpl (p);
303 if (IsPositiveInfinity(retVal) || IsNegativeInfinity(retVal))
304 throw new OverflowException();
311 [MethodImplAttribute(MethodImplOptions.InternalCall)]
312 unsafe private static extern double ParseImpl (byte *byte_ptr);
314 public static bool TryParse (string s,
316 IFormatProvider provider,
320 result = Parse (s, style, provider);
327 public override string ToString ()
329 return ToString (null, null);
332 public string ToString (IFormatProvider fp)
334 return ToString (null, fp);
337 public string ToString (string format)
339 return ToString (format, null);
342 public string ToString (string format, IFormatProvider fp)
344 if (fp is CultureInfo)
345 return DoubleFormatter.NumberToString(format,
346 ((CultureInfo)fp).NumberFormat, value);
348 return DoubleFormatter.NumberToString(format,
349 (NumberFormatInfo)fp, value);
352 // =========== IConvertible Methods =========== //
354 public TypeCode GetTypeCode ()
356 return TypeCode.Double;
359 object IConvertible.ToType (Type conversionType, IFormatProvider provider)
361 return System.Convert.ToType(value, conversionType, provider);
364 bool IConvertible.ToBoolean (IFormatProvider provider)
366 return System.Convert.ToBoolean(value);
369 byte IConvertible.ToByte (IFormatProvider provider)
371 return System.Convert.ToByte(value);
374 char IConvertible.ToChar (IFormatProvider provider)
376 throw new InvalidCastException();
379 [CLSCompliant(false)]
380 DateTime IConvertible.ToDateTime (IFormatProvider provider)
382 throw new InvalidCastException();
385 decimal IConvertible.ToDecimal (IFormatProvider provider)
387 return System.Convert.ToDecimal(value);
390 double IConvertible.ToDouble (IFormatProvider provider)
392 return System.Convert.ToDouble(value);
395 short IConvertible.ToInt16 (IFormatProvider provider)
397 return System.Convert.ToInt16(value);
400 int IConvertible.ToInt32 (IFormatProvider provider)
402 return System.Convert.ToInt32(value);
405 long IConvertible.ToInt64 (IFormatProvider provider)
407 return System.Convert.ToInt64(value);
410 [CLSCompliant(false)]
411 sbyte IConvertible.ToSByte (IFormatProvider provider)
413 return System.Convert.ToSByte(value);
416 float IConvertible.ToSingle (IFormatProvider provider)
418 return System.Convert.ToSingle(value);
422 string IConvertible.ToString (IFormatProvider provider)
424 return ToString(provider);
428 [CLSCompliant(false)]
429 ushort IConvertible.ToUInt16 (IFormatProvider provider)
431 return System.Convert.ToUInt16(value);
434 [CLSCompliant(false)]
435 uint IConvertible.ToUInt32 (IFormatProvider provider)
437 return System.Convert.ToUInt32(value);
440 [CLSCompliant(false)]
441 ulong IConvertible.ToUInt64 (IFormatProvider provider)
443 return System.Convert.ToUInt64(value);