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;
39 using System.Runtime.ConstrainedExecution;
45 public struct Double : IComparable, IFormattable, IConvertible
47 , IComparable <double>, IEquatable <double>
50 public const double Epsilon = 4.9406564584124650e-324;
51 public const double MaxValue = 1.7976931348623157e308;
52 public const double MinValue = -1.7976931348623157e308;
53 public const double NaN = 0.0d / 0.0d;
54 public const double NegativeInfinity = -1.0d / 0.0d;
55 public const double PositiveInfinity = 1.0d / 0.0d;
57 internal double m_value;
59 public int CompareTo (object v)
64 if (!(v is System.Double))
65 throw new ArgumentException (Locale.GetText ("Value is not a System.Double"));
67 double dv = (double)v;
69 if (IsPositiveInfinity(m_value) && IsPositiveInfinity(dv))
72 if (IsNegativeInfinity(m_value) && IsNegativeInfinity(dv))
87 if (m_value > dv) return 1;
88 else if (m_value < dv) return -1;
92 public override bool Equals (object o)
94 if (!(o is System.Double))
97 if (IsNaN ((double)o)) {
104 return ((double) o) == m_value;
108 public int CompareTo (double value)
110 if (IsPositiveInfinity(m_value) && IsPositiveInfinity(value))
113 if (IsNegativeInfinity(m_value) && IsNegativeInfinity(value))
128 if (m_value > value) return 1;
129 else if (m_value < value) return -1;
133 public bool Equals (double value)
142 return value == m_value;
146 public override unsafe int GetHashCode ()
149 return (*((long*)&d)).GetHashCode ();
152 public static bool IsInfinity (double d)
154 return (d == PositiveInfinity || d == NegativeInfinity);
158 [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.Success)]
160 public static bool IsNaN (double d)
162 #pragma warning disable 1718
164 #pragma warning restore
167 public static bool IsNegativeInfinity (double d)
169 return (d < 0.0d && (d == NegativeInfinity || d == PositiveInfinity));
172 public static bool IsPositiveInfinity (double d)
174 return (d > 0.0d && (d == NegativeInfinity || d == PositiveInfinity));
177 public static double Parse (string s)
179 return Parse (s, (NumberStyles.Float | NumberStyles.AllowThousands), null);
182 public static double Parse (string s, IFormatProvider fp)
184 return Parse (s, (NumberStyles.Float | NumberStyles.AllowThousands), fp);
187 public static double Parse (string s, NumberStyles style)
189 return Parse (s, style, null);
192 // We're intentionally using constants here to avoid some bigger headaches in mcs.
193 // This struct must be compiled before System.Enum so we can't use enums here.
194 private const int State_AllowSign = 1;
195 private const int State_Digits = 2;
196 private const int State_Decimal = 3;
197 private const int State_ExponentSign = 4;
198 private const int State_Exponent = 5;
199 private const int State_ConsumeWhiteSpace = 6;
200 private const int State_Exit = 7;
202 public static double Parse (string s, NumberStyles style, IFormatProvider provider)
207 if (!Parse (s, style, provider, false, out result, out exc))
213 [MonoTODO("check if digits are group in correct numbers between the group separators")]
214 internal static bool Parse (string s, NumberStyles style, IFormatProvider provider, bool tryParse, out double result, out Exception exc)
221 exc = new ArgumentNullException ("s");
226 exc = new FormatException ();
230 // yes it's counter intuitive (buggy?) but even TryParse actually throws in this case
231 if ((style & NumberStyles.AllowHexSpecifier) != 0) {
232 string msg = Locale.GetText ("Double doesn't support parsing with '{0}'.", "AllowHexSpecifier");
233 throw new ArgumentException (msg);
236 if (style > NumberStyles.Any) {
238 exc = new ArgumentException();
242 NumberFormatInfo format = NumberFormatInfo.GetInstance(provider);
243 if (format == null) throw new Exception("How did this happen?");
245 if (s == format.NaNSymbol) {
249 if (s == format.PositiveInfinitySymbol) {
250 result = Double.PositiveInfinity;
253 if (s == format.NegativeInfinitySymbol) {
254 result = Double.NegativeInfinity;
259 // validate and prepare string for C
262 byte [] b = new byte [len + 1];
267 if ((style & NumberStyles.AllowLeadingWhite) != 0){
268 while (sidx < len && Char.IsWhiteSpace (c = s [sidx]))
273 exc = Int32.GetFormatException ();
278 bool allow_trailing_white = ((style & NumberStyles.AllowTrailingWhite) != 0);
283 int state = State_AllowSign;
288 string decimal_separator = null;
289 string group_separator = null;
290 string currency_symbol = null;
291 int decimal_separator_len = 0;
292 int group_separator_len = 0;
293 int currency_symbol_len = 0;
294 if ((style & NumberStyles.AllowDecimalPoint) != 0){
295 decimal_separator = format.NumberDecimalSeparator;
296 decimal_separator_len = decimal_separator.Length;
298 if ((style & NumberStyles.AllowThousands) != 0){
299 group_separator = format.NumberGroupSeparator;
300 group_separator_len = group_separator.Length;
302 if ((style & NumberStyles.AllowCurrencySymbol) != 0){
303 currency_symbol = format.CurrencySymbol;
304 currency_symbol_len = currency_symbol.Length;
306 string positive = format.PositiveSign;
307 string negative = format.NegativeSign;
309 for (; sidx < len; sidx++){
318 case State_AllowSign:
319 if ((style & NumberStyles.AllowLeadingSign) != 0){
320 if (c == positive [0] &&
321 s.Substring (sidx, positive.Length) == positive){
322 state = State_Digits;
323 sidx += positive.Length-1;
327 if (c == negative [0] &&
328 s.Substring (sidx, negative.Length) == negative){
329 state = State_Digits;
330 b [didx++] = (byte) '-';
331 sidx += negative.Length-1;
335 state = State_Digits;
336 goto case State_Digits;
339 if (Char.IsDigit (c)){
340 b [didx++] = (byte) c;
343 if (c == 'e' || c == 'E')
344 goto case State_Decimal;
346 if (decimal_separator != null &&
347 decimal_separator [0] == c) {
348 if (String.CompareOrdinal (s, sidx, decimal_separator, 0, decimal_separator_len) == 0) {
349 b [didx++] = (byte) '.';
350 sidx += decimal_separator_len-1;
351 state = State_Decimal;
355 if (group_separator != null &&
356 group_separator [0] == c){
357 if (s.Substring (sidx, group_separator_len) ==
359 sidx += group_separator_len-1;
360 state = State_Digits;
364 if (currency_symbol != null &&
365 currency_symbol [0] == c){
366 if (s.Substring (sidx, currency_symbol_len) ==
368 sidx += currency_symbol_len-1;
369 state = State_Digits;
374 if (Char.IsWhiteSpace (c))
375 goto case State_ConsumeWhiteSpace;
378 exc = new FormatException ("Unknown char: " + c);
382 if (Char.IsDigit (c)){
383 b [didx++] = (byte) c;
387 if (c == 'e' || c == 'E'){
388 if ((style & NumberStyles.AllowExponent) == 0) {
390 exc = new FormatException ("Unknown char: " + c);
393 b [didx++] = (byte) c;
394 state = State_ExponentSign;
398 if (Char.IsWhiteSpace (c))
399 goto case State_ConsumeWhiteSpace;
402 exc = new FormatException ("Unknown char: " + c);
405 case State_ExponentSign:
406 if (Char.IsDigit (c)){
407 state = State_Exponent;
408 goto case State_Exponent;
411 if (c == positive [0] &&
412 s.Substring (sidx, positive.Length) == positive){
413 state = State_Digits;
414 sidx += positive.Length-1;
418 if (c == negative [0] &&
419 s.Substring (sidx, negative.Length) == negative){
420 state = State_Digits;
421 b [didx++] = (byte) '-';
422 sidx += negative.Length-1;
426 if (Char.IsWhiteSpace (c))
427 goto case State_ConsumeWhiteSpace;
430 exc = new FormatException ("Unknown char: " + c);
434 if (Char.IsDigit (c)){
435 b [didx++] = (byte) c;
439 if (Char.IsWhiteSpace (c))
440 goto case State_ConsumeWhiteSpace;
443 exc = new FormatException ("Unknown char: " + c);
446 case State_ConsumeWhiteSpace:
447 if (allow_trailing_white && Char.IsWhiteSpace (c)) {
453 exc = new FormatException ("Unknown char");
457 if (state == State_Exit)
463 fixed (byte *p = &b [0]){
465 if (!ParseImpl (p, out retVal)) {
467 exc = Int32.GetFormatException ();
470 if (IsPositiveInfinity(retVal) || IsNegativeInfinity(retVal)) {
472 exc = new OverflowException ();
482 [MethodImplAttribute(MethodImplOptions.InternalCall)]
483 unsafe private static extern bool ParseImpl (byte *byte_ptr, out double value);
485 public static bool TryParse (string s,
487 IFormatProvider provider,
491 if (!Parse (s, style, provider, true, out result, out exc)) {
499 public static bool TryParse (string s, out double result)
501 return TryParse (s, NumberStyles.Any, null, out result);
504 public override string ToString ()
506 return ToString (null, null);
509 public string ToString (IFormatProvider fp)
511 return ToString (null, fp);
514 public string ToString (string format)
516 return ToString (format, null);
519 public string ToString (string format, IFormatProvider fp)
521 NumberFormatInfo nfi = NumberFormatInfo.GetInstance (fp);
522 return NumberFormatter.NumberToString (format, m_value, nfi);
525 // =========== IConvertible Methods =========== //
527 public TypeCode GetTypeCode ()
529 return TypeCode.Double;
532 object IConvertible.ToType (Type conversionType, IFormatProvider provider)
534 return System.Convert.ToType(m_value, conversionType, provider);
537 bool IConvertible.ToBoolean (IFormatProvider provider)
539 return System.Convert.ToBoolean(m_value);
542 byte IConvertible.ToByte (IFormatProvider provider)
544 return System.Convert.ToByte(m_value);
547 char IConvertible.ToChar (IFormatProvider provider)
549 throw new InvalidCastException();
552 DateTime IConvertible.ToDateTime (IFormatProvider provider)
554 throw new InvalidCastException();
557 decimal IConvertible.ToDecimal (IFormatProvider provider)
559 return System.Convert.ToDecimal(m_value);
562 double IConvertible.ToDouble (IFormatProvider provider)
564 return System.Convert.ToDouble(m_value);
567 short IConvertible.ToInt16 (IFormatProvider provider)
569 return System.Convert.ToInt16(m_value);
572 int IConvertible.ToInt32 (IFormatProvider provider)
574 return System.Convert.ToInt32(m_value);
577 long IConvertible.ToInt64 (IFormatProvider provider)
579 return System.Convert.ToInt64(m_value);
582 sbyte IConvertible.ToSByte (IFormatProvider provider)
584 return System.Convert.ToSByte(m_value);
587 float IConvertible.ToSingle (IFormatProvider provider)
589 return System.Convert.ToSingle(m_value);
593 string IConvertible.ToString (IFormatProvider provider)
595 return ToString(provider);
599 ushort IConvertible.ToUInt16 (IFormatProvider provider)
601 return System.Convert.ToUInt16(m_value);
604 uint IConvertible.ToUInt32 (IFormatProvider provider)
606 return System.Convert.ToUInt32(m_value);
609 ulong IConvertible.ToUInt64 (IFormatProvider provider)
611 return System.Convert.ToUInt64(m_value);