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;
37 using System.Runtime.ConstrainedExecution;
42 [System.Runtime.InteropServices.ComVisible (true)]
43 public struct Double : IComparable, IFormattable, IConvertible, IComparable <double>, IEquatable <double>
45 public const double Epsilon = 4.9406564584124650e-324;
46 public const double MaxValue = 1.7976931348623157e308;
47 public const double MinValue = -1.7976931348623157e308;
48 public const double NaN = 0.0d / 0.0d;
49 public const double NegativeInfinity = -1.0d / 0.0d;
50 public const double PositiveInfinity = 1.0d / 0.0d;
52 internal double m_value;
54 public int CompareTo (object value)
59 if (!(value is System.Double))
60 throw new ArgumentException (Locale.GetText ("Value is not a System.Double"));
62 double dv = (double)value;
64 if (IsPositiveInfinity(m_value) && IsPositiveInfinity(dv))
67 if (IsNegativeInfinity(m_value) && IsNegativeInfinity(dv))
82 if (m_value > dv) return 1;
83 else if (m_value < dv) return -1;
87 public override bool Equals (object obj)
89 if (!(obj is System.Double))
92 double value = (double) obj;
95 return IsNaN (m_value);
97 return (value == m_value);
100 public int CompareTo (double value)
102 if (IsPositiveInfinity(m_value) && IsPositiveInfinity(value))
105 if (IsNegativeInfinity(m_value) && IsNegativeInfinity(value))
120 if (m_value > value) return 1;
121 else if (m_value < value) return -1;
125 public bool Equals (double obj)
134 return obj == m_value;
137 public override unsafe int GetHashCode ()
140 return (*((long*)&d)).GetHashCode ();
144 public static bool operator==(double left, double right)
146 return left == right;
149 public static bool operator!=(double left, double right)
151 return left != right;
154 public static bool operator>(double left, double right)
159 public static bool operator>=(double left, double right)
161 return left >= right;
164 public static bool operator<(double left, double right)
169 public static bool operator<=(double left, double right)
171 return left <= right;
175 public static bool IsInfinity (double d)
177 return (d == PositiveInfinity || d == NegativeInfinity);
180 [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.Success)]
181 public static bool IsNaN (double d)
183 #pragma warning disable 1718
185 #pragma warning restore
188 public static bool IsNegativeInfinity (double d)
190 return (d < 0.0d && (d == NegativeInfinity || d == PositiveInfinity));
193 public static bool IsPositiveInfinity (double d)
195 return (d > 0.0d && (d == NegativeInfinity || d == PositiveInfinity));
198 public static double Parse (string s)
200 return Parse (s, (NumberStyles.Float | NumberStyles.AllowThousands), null);
203 public static double Parse (string s, IFormatProvider provider)
205 return Parse (s, (NumberStyles.Float | NumberStyles.AllowThousands), provider);
208 public static double Parse (string s, NumberStyles style)
210 return Parse (s, style, null);
213 // We're intentionally using constants here to avoid some bigger headaches in mcs.
214 // This struct must be compiled before System.Enum so we can't use enums here.
215 private const int State_AllowSign = 1;
216 private const int State_Digits = 2;
217 private const int State_Decimal = 3;
218 private const int State_ExponentSign = 4;
219 private const int State_Exponent = 5;
220 private const int State_ConsumeWhiteSpace = 6;
221 private const int State_Exit = 7;
223 public static double Parse (string s, NumberStyles style, IFormatProvider provider)
228 if (!Parse (s, style, provider, false, out result, out exc))
234 // FIXME: check if digits are group in correct numbers between the group separators
235 internal static bool Parse (string s, NumberStyles style, IFormatProvider provider, bool tryParse, out double result, out Exception exc)
242 exc = new ArgumentNullException ("s");
247 exc = new FormatException ();
250 // yes it's counter intuitive (buggy?) but even TryParse actually throws in this case
251 if ((style & NumberStyles.AllowHexSpecifier) != 0) {
252 string msg = Locale.GetText ("Double doesn't support parsing with '{0}'.", "AllowHexSpecifier");
253 throw new ArgumentException (msg);
255 if (style > NumberStyles.Any) {
257 exc = new ArgumentException();
261 NumberFormatInfo format = NumberFormatInfo.GetInstance(provider);
262 if (format == null) throw new Exception("How did this happen?");
265 // validate and prepare string for C
271 bool allow_leading_white = (style & NumberStyles.AllowLeadingWhite) != 0;
272 bool allow_trailing_white = ((style & NumberStyles.AllowTrailingWhite) != 0);
274 if (allow_leading_white) {
275 while (sidx < len && Char.IsWhiteSpace (s [sidx]))
280 exc = Int32.GetFormatException ();
284 int sEndPos = s.Length - 1;
285 if (allow_trailing_white)
286 while (Char.IsWhiteSpace (s [sEndPos]))
289 if (TryParseStringConstant (format.NaNSymbol, s, sidx, sEndPos)) {
293 if (TryParseStringConstant (format.PositiveInfinitySymbol, s, sidx, sEndPos)) {
294 result = double.PositiveInfinity;
297 if (TryParseStringConstant (format.NegativeInfinitySymbol, s, sidx, sEndPos)) {
298 result = double.NegativeInfinity;
302 byte [] b = new byte [len + 1];
307 int state = State_AllowSign;
312 string decimal_separator = null;
313 string group_separator = null;
314 string currency_symbol = null;
315 int decimal_separator_len = 0;
316 int group_separator_len = 0;
317 int currency_symbol_len = 0;
318 if ((style & NumberStyles.AllowDecimalPoint) != 0){
319 decimal_separator = format.NumberDecimalSeparator;
320 decimal_separator_len = decimal_separator.Length;
322 if ((style & NumberStyles.AllowThousands) != 0){
323 group_separator = format.NumberGroupSeparator;
324 group_separator_len = group_separator.Length;
326 if ((style & NumberStyles.AllowCurrencySymbol) != 0){
327 currency_symbol = format.CurrencySymbol;
328 currency_symbol_len = currency_symbol.Length;
330 string positive = format.PositiveSign;
331 string negative = format.NegativeSign;
333 for (; sidx < len; sidx++){
342 case State_AllowSign:
343 if ((style & NumberStyles.AllowLeadingSign) != 0){
344 if (c == positive [0] &&
345 s.Substring (sidx, positive.Length) == positive){
346 state = State_Digits;
347 sidx += positive.Length-1;
351 if (c == negative [0] &&
352 s.Substring (sidx, negative.Length) == negative){
353 state = State_Digits;
354 b [didx++] = (byte) '-';
355 sidx += negative.Length-1;
359 state = State_Digits;
360 goto case State_Digits;
363 if (Char.IsDigit (c)){
364 b [didx++] = (byte) c;
367 if (c == 'e' || c == 'E')
368 goto case State_Decimal;
370 if (decimal_separator_len > 0 &&
371 decimal_separator [0] == c) {
372 if (String.CompareOrdinal (s, sidx, decimal_separator, 0, decimal_separator_len) == 0) {
373 b [didx++] = (byte) '.';
374 sidx += decimal_separator_len-1;
375 state = State_Decimal;
379 if (group_separator_len > 0 &&
380 group_separator [0] == c){
381 if (s.Substring (sidx, group_separator_len) ==
383 sidx += group_separator_len-1;
384 state = State_Digits;
388 if (currency_symbol_len > 0 &&
389 currency_symbol [0] == c){
390 if (s.Substring (sidx, currency_symbol_len) ==
392 sidx += currency_symbol_len-1;
393 state = State_Digits;
398 if (Char.IsWhiteSpace (c))
399 goto case State_ConsumeWhiteSpace;
402 exc = new FormatException ("Unknown char: " + c);
406 if (Char.IsDigit (c)){
407 b [didx++] = (byte) c;
411 if (c == 'e' || c == 'E'){
412 if ((style & NumberStyles.AllowExponent) == 0) {
414 exc = new FormatException ("Unknown char: " + c);
417 b [didx++] = (byte) c;
418 state = State_ExponentSign;
422 if (Char.IsWhiteSpace (c))
423 goto case State_ConsumeWhiteSpace;
426 exc = new FormatException ("Unknown char: " + c);
429 case State_ExponentSign:
430 if (Char.IsDigit (c)){
431 state = State_Exponent;
432 goto case State_Exponent;
435 if (c == positive [0] &&
436 s.Substring (sidx, positive.Length) == positive){
437 state = State_Digits;
438 sidx += positive.Length-1;
442 if (c == negative [0] &&
443 s.Substring (sidx, negative.Length) == negative){
444 state = State_Digits;
445 b [didx++] = (byte) '-';
446 sidx += negative.Length-1;
450 if (Char.IsWhiteSpace (c))
451 goto case State_ConsumeWhiteSpace;
454 exc = new FormatException ("Unknown char: " + c);
458 if (Char.IsDigit (c)){
459 b [didx++] = (byte) c;
463 if (Char.IsWhiteSpace (c))
464 goto case State_ConsumeWhiteSpace;
467 exc = new FormatException ("Unknown char: " + c);
470 case State_ConsumeWhiteSpace:
471 if (allow_trailing_white && Char.IsWhiteSpace (c)) {
472 state = State_ConsumeWhiteSpace;
477 exc = new FormatException ("Unknown char");
481 if (state == State_Exit)
487 fixed (byte *p = &b [0]){
489 if (!ParseImpl (p, out retVal)) {
491 exc = Int32.GetFormatException ();
494 if (IsPositiveInfinity(retVal) || IsNegativeInfinity(retVal)) {
496 exc = new OverflowException ();
506 static bool TryParseStringConstant (string format, string s, int start, int end)
508 return end - start + 1 == format.Length && String.CompareOrdinal (format, 0, s, start, format.Length) == 0;
511 [MethodImplAttribute(MethodImplOptions.InternalCall)]
512 unsafe private static extern bool ParseImpl (byte *byte_ptr, out double value);
514 public static bool TryParse (string s,
516 IFormatProvider provider,
520 if (!Parse (s, style, provider, true, out result, out exc)) {
528 public static bool TryParse (string s, out double result)
530 return TryParse (s, NumberStyles.Any, null, out result);
533 public override string ToString ()
535 return NumberFormatter.NumberToString (m_value, null);
538 public string ToString (IFormatProvider provider)
540 return NumberFormatter.NumberToString (m_value, provider);
543 public string ToString (string format)
545 return ToString (format, null);
548 public string ToString (string format, IFormatProvider provider)
550 return NumberFormatter.NumberToString (format, m_value, provider);
553 // =========== IConvertible Methods =========== //
555 public TypeCode GetTypeCode ()
557 return TypeCode.Double;
560 object IConvertible.ToType (Type targetType, IFormatProvider provider)
562 if (targetType == null)
563 throw new ArgumentNullException ("targetType");
564 return System.Convert.ToType (m_value, targetType, provider, false);
567 bool IConvertible.ToBoolean (IFormatProvider provider)
569 return System.Convert.ToBoolean (m_value);
572 byte IConvertible.ToByte (IFormatProvider provider)
574 return System.Convert.ToByte (m_value);
577 char IConvertible.ToChar (IFormatProvider provider)
579 throw new InvalidCastException ();
582 DateTime IConvertible.ToDateTime (IFormatProvider provider)
584 throw new InvalidCastException ();
587 decimal IConvertible.ToDecimal (IFormatProvider provider)
589 return System.Convert.ToDecimal (m_value);
592 double IConvertible.ToDouble (IFormatProvider provider)
594 return System.Convert.ToDouble (m_value);
597 short IConvertible.ToInt16 (IFormatProvider provider)
599 return System.Convert.ToInt16 (m_value);
602 int IConvertible.ToInt32 (IFormatProvider provider)
604 return System.Convert.ToInt32 (m_value);
607 long IConvertible.ToInt64 (IFormatProvider provider)
609 return System.Convert.ToInt64 (m_value);
612 sbyte IConvertible.ToSByte (IFormatProvider provider)
614 return System.Convert.ToSByte (m_value);
617 float IConvertible.ToSingle (IFormatProvider provider)
619 return System.Convert.ToSingle (m_value);
622 ushort IConvertible.ToUInt16 (IFormatProvider provider)
624 return System.Convert.ToUInt16 (m_value);
626 uint IConvertible.ToUInt32 (IFormatProvider provider)
628 return System.Convert.ToUInt32 (m_value);
630 ulong IConvertible.ToUInt64 (IFormatProvider provider)
632 return System.Convert.ToUInt64 (m_value);