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 [MethodImplAttribute(MethodImplOptions.InternalCall)]
29 extern internal static void AssertEndianity (out double value);
31 public int CompareTo (object v)
36 if (!(v is System.Double))
37 throw new ArgumentException (Locale.GetText ("Value is not a System.Double"));
39 double dv = (double)v;
41 if (IsPositiveInfinity(value) && IsPositiveInfinity(dv))
44 if (IsNegativeInfinity(value) && IsNegativeInfinity(dv))
59 if (value > dv) return 1;
60 else if (value < dv) return -1;
64 public override bool Equals (object o)
66 if (!(o is System.Double))
69 if (IsNaN ((double)o)) {
76 return ((double) o) == value;
79 public override int GetHashCode ()
84 public static bool IsInfinity (double d)
86 return (d == PositiveInfinity || d == NegativeInfinity);
89 public static bool IsNaN (double d)
94 public static bool IsNegativeInfinity (double d)
96 return (d < 0.0d && (d == NegativeInfinity || d == PositiveInfinity));
99 public static bool IsPositiveInfinity (double d)
101 return (d > 0.0d && (d == NegativeInfinity || d == PositiveInfinity));
104 public static double Parse (string s)
106 return Parse (s, (NumberStyles.Float | NumberStyles.AllowThousands), null);
109 public static double Parse (string s, IFormatProvider fp)
111 return Parse (s, (NumberStyles.Float | NumberStyles.AllowThousands), fp);
114 public static double Parse (string s, NumberStyles style)
116 return Parse (s, style, null);
119 // We're intentionally using constants here to avoid some bigger headaches in mcs.
120 // This struct must be compiled before System.Enum so we can't use enums here.
121 private const int State_AllowSign = 1;
122 private const int State_Digits = 2;
123 private const int State_Decimal = 3;
124 private const int State_ExponentSign = 4;
125 private const int State_Exponent = 5;
126 private const int State_ConsumeWhiteSpace = 6;
128 [MonoTODO("check if digits are group in correct numbers between the group separators")]
129 public static double Parse (string s, NumberStyles style, IFormatProvider provider)
131 if (s == null) throw new ArgumentNullException();
132 if (style > NumberStyles.Any)
134 throw new ArgumentException();
136 NumberFormatInfo format = NumberFormatInfo.GetInstance(provider);
137 if (format == null) throw new Exception("How did this happen?");
138 if (s == format.NaNSymbol) return Double.NaN;
139 if (s == format.PositiveInfinitySymbol) return Double.PositiveInfinity;
140 if (s == format.NegativeInfinitySymbol) return Double.NegativeInfinity;
143 // validate and prepare string for C
146 byte [] b = new byte [len + 1];
151 if ((style & NumberStyles.AllowLeadingWhite) != 0){
152 while (sidx < len && Char.IsWhiteSpace (c = s [sidx]))
156 throw new FormatException();
159 bool allow_trailing_white = ((style & NumberStyles.AllowTrailingWhite) != 0);
164 int state = State_AllowSign;
169 string decimal_separator = null;
170 string group_separator = null;
171 int decimal_separator_len = 0;
172 int group_separator_len = 0;
173 if ((style & NumberStyles.AllowDecimalPoint) != 0){
174 decimal_separator = format.NumberDecimalSeparator;
175 decimal_separator_len = decimal_separator.Length;
177 if ((style & NumberStyles.AllowThousands) != 0){
178 group_separator = format.NumberGroupSeparator;
179 group_separator_len = group_separator.Length;
181 string positive = format.PositiveSign;
182 string negative = format.NegativeSign;
184 for (; sidx < len; sidx++){
188 case State_AllowSign:
189 if ((style & NumberStyles.AllowLeadingSign) != 0){
190 if (c == positive [0] &&
191 s.Substring (sidx, positive.Length) == positive){
192 state = State_Digits;
193 sidx += positive.Length-1;
197 if (c == negative [0] &&
198 s.Substring (sidx, negative.Length) == negative){
199 state = State_Digits;
200 b [didx++] = (byte) '-';
201 sidx += negative.Length-1;
205 state = State_Digits;
206 goto case State_Digits;
209 if (Char.IsDigit (c)){
210 b [didx++] = (byte) c;
213 if (c == 'e' || c == 'E')
214 goto case State_Decimal;
216 if (decimal_separator != null &&
217 decimal_separator [0] == c){
218 if (s.Substring (sidx, decimal_separator_len) ==
220 b [didx++] = (byte) '.';
221 sidx += decimal_separator_len-1;
222 state = State_Decimal;
226 if (group_separator != null &&
227 group_separator [0] == c){
228 if (s.Substring (sidx, group_separator_len) ==
230 sidx += group_separator_len-1;
231 state = State_Digits;
236 if (Char.IsWhiteSpace (c))
237 goto case State_ConsumeWhiteSpace;
239 throw new FormatException ("Unknown char: " + c);
242 if (Char.IsDigit (c)){
243 b [didx++] = (byte) c;
247 if (c == 'e' || c == 'E'){
248 if ((style & NumberStyles.AllowExponent) == 0)
249 throw new FormatException ("Unknown char: " + c);
250 b [didx++] = (byte) c;
251 state = State_ExponentSign;
255 if (Char.IsWhiteSpace (c))
256 goto case State_ConsumeWhiteSpace;
257 throw new FormatException ("Unknown char: " + c);
259 case State_ExponentSign:
260 if (Char.IsDigit (c)){
261 state = State_Exponent;
262 goto case State_Exponent;
265 if (c == positive [0] &&
266 s.Substring (sidx, positive.Length) == positive){
267 state = State_Digits;
268 sidx += positive.Length-1;
272 if (c == negative [0] &&
273 s.Substring (sidx, negative.Length) == negative){
274 state = State_Digits;
275 b [didx++] = (byte) '-';
276 sidx += negative.Length-1;
280 if (Char.IsWhiteSpace (c))
281 goto case State_ConsumeWhiteSpace;
283 throw new FormatException ("Unknown char: " + c);
286 if (Char.IsDigit (c)){
287 b [didx++] = (byte) c;
291 if (Char.IsWhiteSpace (c))
292 goto case State_ConsumeWhiteSpace;
293 throw new FormatException ("Unknown char: " + c);
295 case State_ConsumeWhiteSpace:
296 if (allow_trailing_white && Char.IsWhiteSpace (c))
298 throw new FormatException ("Unknown char");
304 fixed (byte *p = &b [0]){
305 double retVal = ParseImpl (p);
306 if (IsPositiveInfinity(retVal) || IsNegativeInfinity(retVal))
307 throw new OverflowException();
314 [MethodImplAttribute(MethodImplOptions.InternalCall)]
315 unsafe private static extern double ParseImpl (byte *byte_ptr);
317 public static bool TryParse (string s,
319 IFormatProvider provider,
323 result = Parse (s, style, provider);
330 public override string ToString ()
332 return ToString (null, null);
335 public string ToString (IFormatProvider fp)
337 return ToString (null, fp);
340 public string ToString (string format)
342 return ToString (format, null);
345 public string ToString (string format, IFormatProvider fp)
347 if (fp is CultureInfo)
348 return DoubleFormatter.NumberToString(format,
349 ((CultureInfo)fp).NumberFormat, value);
351 return DoubleFormatter.NumberToString(format,
352 (NumberFormatInfo)fp, value);
355 // =========== IConvertible Methods =========== //
357 public TypeCode GetTypeCode ()
359 return TypeCode.Double;
362 object IConvertible.ToType (Type conversionType, IFormatProvider provider)
364 return System.Convert.ToType(value, conversionType, provider);
367 bool IConvertible.ToBoolean (IFormatProvider provider)
369 return System.Convert.ToBoolean(value);
372 byte IConvertible.ToByte (IFormatProvider provider)
374 return System.Convert.ToByte(value);
377 char IConvertible.ToChar (IFormatProvider provider)
379 throw new InvalidCastException();
382 [CLSCompliant(false)]
383 DateTime IConvertible.ToDateTime (IFormatProvider provider)
385 throw new InvalidCastException();
388 decimal IConvertible.ToDecimal (IFormatProvider provider)
390 return System.Convert.ToDecimal(value);
393 double IConvertible.ToDouble (IFormatProvider provider)
395 return System.Convert.ToDouble(value);
398 short IConvertible.ToInt16 (IFormatProvider provider)
400 return System.Convert.ToInt16(value);
403 int IConvertible.ToInt32 (IFormatProvider provider)
405 return System.Convert.ToInt32(value);
408 long IConvertible.ToInt64 (IFormatProvider provider)
410 return System.Convert.ToInt64(value);
413 [CLSCompliant(false)]
414 sbyte IConvertible.ToSByte (IFormatProvider provider)
416 return System.Convert.ToSByte(value);
419 float IConvertible.ToSingle (IFormatProvider provider)
421 return System.Convert.ToSingle(value);
425 string IConvertible.ToString (IFormatProvider provider)
427 return ToString(provider);
431 [CLSCompliant(false)]
432 ushort IConvertible.ToUInt16 (IFormatProvider provider)
434 return System.Convert.ToUInt16(value);
437 [CLSCompliant(false)]
438 uint IConvertible.ToUInt32 (IFormatProvider provider)
440 return System.Convert.ToUInt32(value);
443 [CLSCompliant(false)]
444 ulong IConvertible.ToUInt64 (IFormatProvider provider)
446 return System.Convert.ToUInt64(value);