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
13 // Copyright (C) 2004 Novell, Inc (http://www.novell.com)
15 // Permission is hereby granted, free of charge, to any person obtaining
16 // a copy of this software and associated documentation files (the
17 // "Software"), to deal in the Software without restriction, including
18 // without limitation the rights to use, copy, modify, merge, publish,
19 // distribute, sublicense, and/or sell copies of the Software, and to
20 // permit persons to whom the Software is furnished to do so, subject to
21 // the following conditions:
23 // The above copyright notice and this permission notice shall be
24 // included in all copies or substantial portions of the Software.
26 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
27 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
28 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
29 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
30 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
31 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
32 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
35 using System.Globalization;
36 using System.Runtime.CompilerServices;
41 public struct Double : IComparable, IFormattable, IConvertible
43 , IComparable <double>
46 public const double Epsilon = 4.9406564584124650e-324;
47 public const double MaxValue = 1.7976931348623157e308;
48 public const double MinValue = -1.7976931348623157e308;
49 public const double NaN = 0.0d / 0.0d;
50 public const double NegativeInfinity = -1.0d / 0.0d;
51 public const double PositiveInfinity = 1.0d / 0.0d;
53 internal double m_value;
55 [MethodImplAttribute(MethodImplOptions.InternalCall)]
56 extern internal static void AssertEndianity (out double value);
58 public int CompareTo (object v)
63 if (!(v is System.Double))
64 throw new ArgumentException (Locale.GetText ("Value is not a System.Double"));
66 double dv = (double)v;
68 if (IsPositiveInfinity(m_value) && IsPositiveInfinity(dv))
71 if (IsNegativeInfinity(m_value) && IsNegativeInfinity(dv))
86 if (m_value > dv) return 1;
87 else if (m_value < dv) return -1;
91 public override bool Equals (object o)
93 if (!(o is System.Double))
96 if (IsNaN ((double)o)) {
103 return ((double) o) == m_value;
107 public int CompareTo (double value)
109 if (IsPositiveInfinity(m_value) && IsPositiveInfinity(value))
112 if (IsNegativeInfinity(m_value) && IsNegativeInfinity(value))
127 if (m_value > value) return 1;
128 else if (m_value < value) return -1;
132 public bool Equals (double value)
141 return value == m_value;
145 public override unsafe int GetHashCode ()
148 return (*((long*)&d)).GetHashCode ();
151 public static bool IsInfinity (double d)
153 return (d == PositiveInfinity || d == NegativeInfinity);
156 public static bool IsNaN (double d)
161 public static bool IsNegativeInfinity (double d)
163 return (d < 0.0d && (d == NegativeInfinity || d == PositiveInfinity));
166 public static bool IsPositiveInfinity (double d)
168 return (d > 0.0d && (d == NegativeInfinity || d == PositiveInfinity));
171 public static double Parse (string s)
173 return Parse (s, (NumberStyles.Float | NumberStyles.AllowThousands), null);
176 public static double Parse (string s, IFormatProvider fp)
178 return Parse (s, (NumberStyles.Float | NumberStyles.AllowThousands), fp);
181 public static double Parse (string s, NumberStyles style)
183 return Parse (s, style, null);
186 // We're intentionally using constants here to avoid some bigger headaches in mcs.
187 // This struct must be compiled before System.Enum so we can't use enums here.
188 private const int State_AllowSign = 1;
189 private const int State_Digits = 2;
190 private const int State_Decimal = 3;
191 private const int State_ExponentSign = 4;
192 private const int State_Exponent = 5;
193 private const int State_ConsumeWhiteSpace = 6;
195 [MonoTODO("check if digits are group in correct numbers between the group separators")]
196 public static double Parse (string s, NumberStyles style, IFormatProvider provider)
198 if (s == null) throw new ArgumentNullException();
199 if (style > NumberStyles.Any)
201 throw new ArgumentException();
203 NumberFormatInfo format = NumberFormatInfo.GetInstance(provider);
204 if (format == null) throw new Exception("How did this happen?");
205 if (s == format.NaNSymbol) return Double.NaN;
206 if (s == format.PositiveInfinitySymbol) return Double.PositiveInfinity;
207 if (s == format.NegativeInfinitySymbol) return Double.NegativeInfinity;
210 // validate and prepare string for C
213 byte [] b = new byte [len + 1];
218 if ((style & NumberStyles.AllowLeadingWhite) != 0){
219 while (sidx < len && Char.IsWhiteSpace (c = s [sidx]))
223 throw new FormatException();
226 bool allow_trailing_white = ((style & NumberStyles.AllowTrailingWhite) != 0);
231 int state = State_AllowSign;
236 string decimal_separator = null;
237 string group_separator = null;
238 int decimal_separator_len = 0;
239 int group_separator_len = 0;
240 if ((style & NumberStyles.AllowDecimalPoint) != 0){
241 decimal_separator = format.NumberDecimalSeparator;
242 decimal_separator_len = decimal_separator.Length;
244 if ((style & NumberStyles.AllowThousands) != 0){
245 group_separator = format.NumberGroupSeparator;
246 group_separator_len = group_separator.Length;
248 string positive = format.PositiveSign;
249 string negative = format.NegativeSign;
251 for (; sidx < len; sidx++){
259 case State_AllowSign:
260 if ((style & NumberStyles.AllowLeadingSign) != 0){
261 if (c == positive [0] &&
262 s.Substring (sidx, positive.Length) == positive){
263 state = State_Digits;
264 sidx += positive.Length-1;
268 if (c == negative [0] &&
269 s.Substring (sidx, negative.Length) == negative){
270 state = State_Digits;
271 b [didx++] = (byte) '-';
272 sidx += negative.Length-1;
276 state = State_Digits;
277 goto case State_Digits;
280 if (Char.IsDigit (c)){
281 b [didx++] = (byte) c;
284 if (c == 'e' || c == 'E')
285 goto case State_Decimal;
287 if (decimal_separator != null &&
288 decimal_separator [0] == c){
289 if (s.Substring (sidx, decimal_separator_len) ==
291 b [didx++] = (byte) '.';
292 sidx += decimal_separator_len-1;
293 state = State_Decimal;
297 if (group_separator != null &&
298 group_separator [0] == c){
299 if (s.Substring (sidx, group_separator_len) ==
301 sidx += group_separator_len-1;
302 state = State_Digits;
307 if (Char.IsWhiteSpace (c))
308 goto case State_ConsumeWhiteSpace;
310 throw new FormatException ("Unknown char: " + c);
313 if (Char.IsDigit (c)){
314 b [didx++] = (byte) c;
318 if (c == 'e' || c == 'E'){
319 if ((style & NumberStyles.AllowExponent) == 0)
320 throw new FormatException ("Unknown char: " + c);
321 b [didx++] = (byte) c;
322 state = State_ExponentSign;
326 if (Char.IsWhiteSpace (c))
327 goto case State_ConsumeWhiteSpace;
328 throw new FormatException ("Unknown char: " + c);
330 case State_ExponentSign:
331 if (Char.IsDigit (c)){
332 state = State_Exponent;
333 goto case State_Exponent;
336 if (c == positive [0] &&
337 s.Substring (sidx, positive.Length) == positive){
338 state = State_Digits;
339 sidx += positive.Length-1;
343 if (c == negative [0] &&
344 s.Substring (sidx, negative.Length) == negative){
345 state = State_Digits;
346 b [didx++] = (byte) '-';
347 sidx += negative.Length-1;
351 if (Char.IsWhiteSpace (c))
352 goto case State_ConsumeWhiteSpace;
354 throw new FormatException ("Unknown char: " + c);
357 if (Char.IsDigit (c)){
358 b [didx++] = (byte) c;
362 if (Char.IsWhiteSpace (c))
363 goto case State_ConsumeWhiteSpace;
364 throw new FormatException ("Unknown char: " + c);
366 case State_ConsumeWhiteSpace:
367 if (allow_trailing_white && Char.IsWhiteSpace (c))
369 throw new FormatException ("Unknown char");
375 fixed (byte *p = &b [0]){
376 double retVal = ParseImpl (p);
377 if (IsPositiveInfinity(retVal) || IsNegativeInfinity(retVal))
378 throw new OverflowException();
385 [MethodImplAttribute(MethodImplOptions.InternalCall)]
386 unsafe private static extern double ParseImpl (byte *byte_ptr);
388 public static bool TryParse (string s,
390 IFormatProvider provider,
394 result = Parse (s, style, provider);
402 public override string ToString ()
404 return ToString (null, null);
407 public string ToString (IFormatProvider fp)
409 return ToString (null, fp);
412 public string ToString (string format)
414 return ToString (format, null);
417 public string ToString (string format, IFormatProvider fp)
419 NumberFormatInfo nfi = fp != null ? fp.GetFormat (typeof (NumberFormatInfo)) as NumberFormatInfo : null;
420 return DoubleFormatter.NumberToString (format, nfi, m_value);
423 // =========== IConvertible Methods =========== //
425 public TypeCode GetTypeCode ()
427 return TypeCode.Double;
430 object IConvertible.ToType (Type conversionType, IFormatProvider provider)
432 return System.Convert.ToType(m_value, conversionType, provider);
435 bool IConvertible.ToBoolean (IFormatProvider provider)
437 return System.Convert.ToBoolean(m_value);
440 byte IConvertible.ToByte (IFormatProvider provider)
442 return System.Convert.ToByte(m_value);
445 char IConvertible.ToChar (IFormatProvider provider)
447 throw new InvalidCastException();
450 DateTime IConvertible.ToDateTime (IFormatProvider provider)
452 throw new InvalidCastException();
455 decimal IConvertible.ToDecimal (IFormatProvider provider)
457 return System.Convert.ToDecimal(m_value);
460 double IConvertible.ToDouble (IFormatProvider provider)
462 return System.Convert.ToDouble(m_value);
465 short IConvertible.ToInt16 (IFormatProvider provider)
467 return System.Convert.ToInt16(m_value);
470 int IConvertible.ToInt32 (IFormatProvider provider)
472 return System.Convert.ToInt32(m_value);
475 long IConvertible.ToInt64 (IFormatProvider provider)
477 return System.Convert.ToInt64(m_value);
480 sbyte IConvertible.ToSByte (IFormatProvider provider)
482 return System.Convert.ToSByte(m_value);
485 float IConvertible.ToSingle (IFormatProvider provider)
487 return System.Convert.ToSingle(m_value);
491 string IConvertible.ToString (IFormatProvider provider)
493 return ToString(provider);
497 ushort IConvertible.ToUInt16 (IFormatProvider provider)
499 return System.Convert.ToUInt16(m_value);
502 uint IConvertible.ToUInt32 (IFormatProvider provider)
504 return System.Convert.ToUInt32(m_value);
507 ulong IConvertible.ToUInt64 (IFormatProvider provider)
509 return System.Convert.ToUInt64(m_value);