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 // VES needs to know about value. public is workaround
27 // so source will compile
30 public int CompareTo (object v)
35 if (!(v is System.Double))
36 throw new ArgumentException (Locale.GetText ("Value is not a System.Double"));
38 if (IsPositiveInfinity(value) && IsPositiveInfinity((double) v)){
42 if (IsNegativeInfinity(value) && IsNegativeInfinity((double) v)){
46 if (IsNaN((double) v)) {
53 return (int) (value - ((double) v));
56 public override bool Equals (object o)
58 if (!(o is System.Double))
61 if (IsNaN ((double)o)) {
68 return ((double) o) == value;
71 public override int GetHashCode ()
76 public static bool IsInfinity (double d)
78 return (d == PositiveInfinity || d == NegativeInfinity);
81 public static bool IsNaN (double d)
86 public static bool IsNegativeInfinity (double d)
88 return (d < 0.0d && (d == NegativeInfinity || d == PositiveInfinity));
91 public static bool IsPositiveInfinity (double d)
93 return (d > 0.0d && (d == NegativeInfinity || d == PositiveInfinity));
96 public static double Parse (string s)
98 return Parse (s, (NumberStyles.Float | NumberStyles.AllowThousands), null);
101 public static double Parse (string s, IFormatProvider fp)
103 return Parse (s, (NumberStyles.Float | NumberStyles.AllowThousands), fp);
106 public static double Parse (string s, NumberStyles style)
108 return Parse (s, style, null);
111 // We're intentionally using constants here to avoid some bigger headaches in mcs.
112 // This struct must be compiled before System.Enum so we can't use enums here.
113 private const int State_AllowSign = 1;
114 private const int State_Digits = 2;
115 private const int State_Decimal = 3;
116 private const int State_ExponentSign = 4;
117 private const int State_Exponent = 5;
118 private const int State_ConsumeWhiteSpace = 6;
120 [MonoTODO("check if digits are group in correct numbers between the group separators")]
121 public static double Parse (string s, NumberStyles style, IFormatProvider provider)
123 if (s == null) throw new ArgumentNullException();
124 if (style > NumberStyles.Any)
126 throw new ArgumentException();
128 NumberFormatInfo format = NumberFormatInfo.GetInstance(provider);
129 if (format == null) throw new Exception("How did this happen?");
130 if (s == format.NaNSymbol) return Double.NaN;
131 if (s == format.PositiveInfinitySymbol) return Double.PositiveInfinity;
132 if (s == format.NegativeInfinitySymbol) return Double.NegativeInfinity;
135 // validate and prepare string for C
138 byte [] b = new byte [len + 1];
143 if ((style & NumberStyles.AllowLeadingWhite) != 0){
144 while (sidx < len && Char.IsWhiteSpace (c = s [sidx]))
148 throw new FormatException();
151 bool allow_trailing_white = ((style & NumberStyles.AllowTrailingWhite) != 0);
156 int state = State_AllowSign;
161 string decimal_separator = null;
162 string group_separator = null;
163 int decimal_separator_len = 0;
164 int group_separator_len = 0;
165 if ((style & NumberStyles.AllowDecimalPoint) != 0){
166 decimal_separator = format.NumberDecimalSeparator;
167 decimal_separator_len = decimal_separator.Length;
169 if ((style & NumberStyles.AllowThousands) != 0){
170 group_separator = format.NumberGroupSeparator;
171 group_separator_len = group_separator.Length;
173 string positive = format.PositiveSign;
174 string negative = format.NegativeSign;
176 for (; sidx < len; sidx++){
180 case State_AllowSign:
181 if ((style & NumberStyles.AllowLeadingSign) != 0){
182 if (c == positive [0] &&
183 s.Substring (sidx, positive.Length) == positive){
184 state = State_Digits;
185 sidx += positive.Length-1;
189 if (c == negative [0] &&
190 s.Substring (sidx, negative.Length) == negative){
191 state = State_Digits;
192 b [didx++] = (byte) '-';
193 sidx += negative.Length-1;
197 state = State_Digits;
198 goto case State_Digits;
201 if (Char.IsDigit (c)){
202 b [didx++] = (byte) c;
205 if (c == 'e' || c == 'E')
206 goto case State_Decimal;
208 if (decimal_separator != null &&
209 decimal_separator [0] == c){
210 if (s.Substring (sidx, decimal_separator_len) ==
212 b [didx++] = (byte) '.';
213 sidx += decimal_separator_len-1;
214 state = State_Decimal;
218 if (group_separator != null &&
219 group_separator [0] == c){
220 if (s.Substring (sidx, group_separator_len) ==
222 sidx += group_separator_len-1;
223 state = State_Digits;
228 if (Char.IsWhiteSpace (c))
229 goto case State_ConsumeWhiteSpace;
231 throw new FormatException ("Unknown char: " + c);
234 if (Char.IsDigit (c)){
235 b [didx++] = (byte) c;
239 if (c == 'e' || c == 'E'){
240 if ((style & NumberStyles.AllowExponent) == 0)
241 throw new FormatException ("Unknown char: " + c);
242 b [didx++] = (byte) c;
243 state = State_ExponentSign;
247 if (Char.IsWhiteSpace (c))
248 goto case State_ConsumeWhiteSpace;
249 throw new FormatException ("Unknown char: " + c);
251 case State_ExponentSign:
252 if (Char.IsDigit (c)){
253 state = State_Exponent;
254 goto case State_Exponent;
257 if (c == positive [0] &&
258 s.Substring (sidx, positive.Length) == positive){
259 state = State_Digits;
260 sidx += positive.Length-1;
264 if (c == negative [0] &&
265 s.Substring (sidx, negative.Length) == negative){
266 state = State_Digits;
267 b [didx++] = (byte) '-';
268 sidx += negative.Length-1;
272 if (Char.IsWhiteSpace (c))
273 goto case State_ConsumeWhiteSpace;
275 throw new FormatException ("Unknown char: " + c);
278 if (Char.IsDigit (c)){
279 b [didx++] = (byte) c;
283 if (Char.IsWhiteSpace (c))
284 goto case State_ConsumeWhiteSpace;
285 throw new FormatException ("Unknown char: " + c);
287 case State_ConsumeWhiteSpace:
288 if (allow_trailing_white && Char.IsWhiteSpace (c))
290 throw new FormatException ("Unknown char");
296 fixed (byte *p = &b [0]){
297 double retVal = ParseImpl (p);
298 if (IsPositiveInfinity(retVal) || IsNegativeInfinity(retVal))
299 throw new OverflowException();
306 [MethodImplAttribute(MethodImplOptions.InternalCall)]
307 unsafe private static extern double ParseImpl (byte *byte_ptr);
309 public override string ToString ()
311 return ToString (null, null);
314 public string ToString (IFormatProvider fp)
316 return ToString (null, fp);
319 public string ToString (string format)
321 return ToString (format, null);
325 public string ToString (string format, IFormatProvider fp)
327 // FIXME: Need to pass format and provider info to this call too.
328 return ToStringImpl(value);
331 [MethodImplAttribute(MethodImplOptions.InternalCall)]
332 private static extern string ToStringImpl (double value);
334 // =========== IConvertible Methods =========== //
336 public TypeCode GetTypeCode ()
338 return TypeCode.Double;
341 object IConvertible.ToType (Type conversionType, IFormatProvider provider)
343 return System.Convert.ToType(value, conversionType, provider);
346 bool IConvertible.ToBoolean (IFormatProvider provider)
348 return System.Convert.ToBoolean(value);
351 byte IConvertible.ToByte (IFormatProvider provider)
353 return System.Convert.ToByte(value);
356 char IConvertible.ToChar (IFormatProvider provider)
358 throw new InvalidCastException();
361 [CLSCompliant(false)]
362 DateTime IConvertible.ToDateTime (IFormatProvider provider)
364 throw new InvalidCastException();
367 decimal IConvertible.ToDecimal (IFormatProvider provider)
369 return System.Convert.ToDecimal(value);
372 double IConvertible.ToDouble (IFormatProvider provider)
374 return System.Convert.ToDouble(value);
377 short IConvertible.ToInt16 (IFormatProvider provider)
379 return System.Convert.ToInt16(value);
382 int IConvertible.ToInt32 (IFormatProvider provider)
384 return System.Convert.ToInt32(value);
387 long IConvertible.ToInt64 (IFormatProvider provider)
389 return System.Convert.ToInt64(value);
392 [CLSCompliant(false)]
393 sbyte IConvertible.ToSByte (IFormatProvider provider)
395 return System.Convert.ToSByte(value);
398 float IConvertible.ToSingle (IFormatProvider provider)
400 return System.Convert.ToSingle(value);
404 string IConvertible.ToString (IFormatProvider provider)
406 return ToString(provider);
410 [CLSCompliant(false)]
411 ushort IConvertible.ToUInt16 (IFormatProvider provider)
413 return System.Convert.ToUInt16(value);
416 [CLSCompliant(false)]
417 uint IConvertible.ToUInt32 (IFormatProvider provider)
419 return System.Convert.ToUInt32(value);
422 [CLSCompliant(false)]
423 ulong IConvertible.ToUInt64 (IFormatProvider provider)
425 return System.Convert.ToUInt64(value);