Fix default style argument to Double/Single/Decimal.Parse (#17556)
[platform/upstream/coreclr.git] / src / mscorlib / shared / System / Single.cs
1 // Licensed to the .NET Foundation under one or more agreements.
2 // The .NET Foundation licenses this file to you under the MIT license.
3 // See the LICENSE file in the project root for more information.
4
5 /*============================================================
6 **
7 **
8 **
9 ** Purpose: A wrapper class for the primitive type float.
10 **
11 **
12 ===========================================================*/
13
14 using System.Globalization;
15 using System.Runtime.CompilerServices;
16 using System.Runtime.InteropServices;
17 using System.Runtime.Versioning;
18
19 using Internal.Runtime.CompilerServices;
20
21 namespace System
22 {
23     [Serializable]
24     [StructLayout(LayoutKind.Sequential)]
25     [TypeForwardedFrom("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")]
26     public struct Single : IComparable, IConvertible, IFormattable, IComparable<Single>, IEquatable<Single>, ISpanFormattable
27     {
28         private float m_value; // Do not rename (binary serialization)
29
30         //
31         // Public constants
32         //
33         public const float MinValue = (float)-3.40282346638528859e+38;
34         public const float Epsilon = (float)1.4e-45;
35         public const float MaxValue = (float)3.40282346638528859e+38;
36         public const float PositiveInfinity = (float)1.0 / (float)0.0;
37         public const float NegativeInfinity = (float)-1.0 / (float)0.0;
38         public const float NaN = (float)0.0 / (float)0.0;
39
40         // We use this explicit definition to avoid the confusion between 0.0 and -0.0.
41         internal const float NegativeZero = (float)-0.0;
42
43         /// <summary>Determines whether the specified value is finite (zero, subnormal, or normal).</summary>
44         [NonVersionable]
45         [MethodImpl(MethodImplOptions.AggressiveInlining)]
46         public static bool IsFinite(float f)
47         {
48             var bits = BitConverter.SingleToInt32Bits(f);
49             return (bits & 0x7FFFFFFF) < 0x7F800000;
50         }
51
52         /// <summary>Determines whether the specified value is infinite.</summary>
53         [NonVersionable]
54         [MethodImpl(MethodImplOptions.AggressiveInlining)]
55         public static unsafe bool IsInfinity(float f)
56         {
57             var bits = BitConverter.SingleToInt32Bits(f);
58             return (bits & 0x7FFFFFFF) == 0x7F800000;
59         }
60
61         /// <summary>Determines whether the specified value is NaN.</summary>
62         [NonVersionable]
63         [MethodImpl(MethodImplOptions.AggressiveInlining)]
64         public static unsafe bool IsNaN(float f)
65         {
66             var bits = BitConverter.SingleToInt32Bits(f);
67             return (bits & 0x7FFFFFFF) > 0x7F800000;
68         }
69
70         /// <summary>Determines whether the specified value is negative.</summary>
71         [NonVersionable]
72         [MethodImpl(MethodImplOptions.AggressiveInlining)]
73         public static unsafe bool IsNegative(float f)
74         {
75             var bits = unchecked((uint)BitConverter.SingleToInt32Bits(f));
76             return (bits & 0x80000000) == 0x80000000;
77         }
78
79         /// <summary>Determines whether the specified value is negative infinity.</summary>
80         [NonVersionable]
81         [MethodImpl(MethodImplOptions.AggressiveInlining)]
82         public static unsafe bool IsNegativeInfinity(float f)
83         {
84             return (f == float.NegativeInfinity);
85         }
86
87         /// <summary>Determines whether the specified value is normal.</summary>
88         [NonVersionable]
89         // This is probably not worth inlining, it has branches and should be rarely called
90         public static unsafe bool IsNormal(float f)
91         {
92             var bits = BitConverter.SingleToInt32Bits(f);
93             bits &= 0x7FFFFFFF;
94             return (bits < 0x7F800000) && (bits != 0) && ((bits & 0x7F800000) != 0);
95         }
96
97         /// <summary>Determines whether the specified value is positive infinity.</summary>
98         [NonVersionable]
99         [MethodImpl(MethodImplOptions.AggressiveInlining)]
100         public static unsafe bool IsPositiveInfinity(float f)
101         {
102             return (f == float.PositiveInfinity);
103         }
104
105         /// <summary>Determines whether the specified value is subnormal.</summary>
106         [NonVersionable]
107         // This is probably not worth inlining, it has branches and should be rarely called
108         public static unsafe bool IsSubnormal(float f)
109         {
110             var bits = BitConverter.SingleToInt32Bits(f);
111             bits &= 0x7FFFFFFF;
112             return (bits < 0x7F800000) && (bits != 0) && ((bits & 0x7F800000) == 0);
113         }
114
115         // Compares this object to another object, returning an integer that
116         // indicates the relationship.
117         // Returns a value less than zero if this  object
118         // null is considered to be less than any instance.
119         // If object is not of type Single, this method throws an ArgumentException.
120         //
121         public int CompareTo(Object value)
122         {
123             if (value == null)
124             {
125                 return 1;
126             }
127             if (value is Single)
128             {
129                 float f = (float)value;
130                 if (m_value < f) return -1;
131                 if (m_value > f) return 1;
132                 if (m_value == f) return 0;
133
134                 // At least one of the values is NaN.
135                 if (IsNaN(m_value))
136                     return (IsNaN(f) ? 0 : -1);
137                 else // f is NaN.
138                     return 1;
139             }
140             throw new ArgumentException(SR.Arg_MustBeSingle);
141         }
142
143
144         public int CompareTo(Single value)
145         {
146             if (m_value < value) return -1;
147             if (m_value > value) return 1;
148             if (m_value == value) return 0;
149
150             // At least one of the values is NaN.
151             if (IsNaN(m_value))
152                 return (IsNaN(value) ? 0 : -1);
153             else // f is NaN.
154                 return 1;
155         }
156
157         [NonVersionable]
158         public static bool operator ==(Single left, Single right)
159         {
160             return left == right;
161         }
162
163         [NonVersionable]
164         public static bool operator !=(Single left, Single right)
165         {
166             return left != right;
167         }
168
169         [NonVersionable]
170         public static bool operator <(Single left, Single right)
171         {
172             return left < right;
173         }
174
175         [NonVersionable]
176         public static bool operator >(Single left, Single right)
177         {
178             return left > right;
179         }
180
181         [NonVersionable]
182         public static bool operator <=(Single left, Single right)
183         {
184             return left <= right;
185         }
186
187         [NonVersionable]
188         public static bool operator >=(Single left, Single right)
189         {
190             return left >= right;
191         }
192
193         public override bool Equals(Object obj)
194         {
195             if (!(obj is Single))
196             {
197                 return false;
198             }
199             float temp = ((Single)obj).m_value;
200             if (temp == m_value)
201             {
202                 return true;
203             }
204
205             return IsNaN(temp) && IsNaN(m_value);
206         }
207
208         public bool Equals(Single obj)
209         {
210             if (obj == m_value)
211             {
212                 return true;
213             }
214
215             return IsNaN(obj) && IsNaN(m_value);
216         }
217
218         public override int GetHashCode()
219         {
220             var bits = Unsafe.As<float, int>(ref m_value);
221
222             // Optimized check for IsNan() || IsZero()
223             if (((bits - 1) & 0x7FFFFFFF) >= 0x7F800000)
224             {
225                 // Ensure that all NaNs and both zeros have the same hash code
226                 bits &= 0x7F800000;
227             }
228
229             return bits;
230         }
231
232         public override String ToString()
233         {
234             return Number.FormatSingle(m_value, null, NumberFormatInfo.CurrentInfo);
235         }
236
237         public String ToString(IFormatProvider provider)
238         {
239             return Number.FormatSingle(m_value, null, NumberFormatInfo.GetInstance(provider));
240         }
241
242         public String ToString(String format)
243         {
244             return Number.FormatSingle(m_value, format, NumberFormatInfo.CurrentInfo);
245         }
246
247         public String ToString(String format, IFormatProvider provider)
248         {
249             return Number.FormatSingle(m_value, format, NumberFormatInfo.GetInstance(provider));
250         }
251
252         public bool TryFormat(Span<char> destination, out int charsWritten, ReadOnlySpan<char> format = default, IFormatProvider provider = null)
253         {
254             return Number.TryFormatSingle(m_value, format, NumberFormatInfo.GetInstance(provider), destination, out charsWritten);
255         }
256
257         // Parses a float from a String in the given style.  If
258         // a NumberFormatInfo isn't specified, the current culture's
259         // NumberFormatInfo is assumed.
260         //
261         // This method will not throw an OverflowException, but will return
262         // PositiveInfinity or NegativeInfinity for a number that is too
263         // large or too small.
264         //
265         public static float Parse(String s)
266         {
267             if (s == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.s);
268             return Number.ParseSingle(s, NumberStyles.Float | NumberStyles.AllowThousands, NumberFormatInfo.CurrentInfo);
269         }
270
271         public static float Parse(String s, NumberStyles style)
272         {
273             NumberFormatInfo.ValidateParseStyleFloatingPoint(style);
274             if (s == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.s);
275             return Number.ParseSingle(s, style, NumberFormatInfo.CurrentInfo);
276         }
277
278         public static float Parse(String s, IFormatProvider provider)
279         {
280             if (s == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.s);
281             return Number.ParseSingle(s, NumberStyles.Float | NumberStyles.AllowThousands, NumberFormatInfo.GetInstance(provider));
282         }
283
284         public static float Parse(String s, NumberStyles style, IFormatProvider provider)
285         {
286             NumberFormatInfo.ValidateParseStyleFloatingPoint(style);
287             if (s == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.s);
288             return Number.ParseSingle(s, style, NumberFormatInfo.GetInstance(provider));
289         }
290
291         public static float Parse(ReadOnlySpan<char> s, NumberStyles style = NumberStyles.Float | NumberStyles.AllowThousands, IFormatProvider provider = null)
292         {
293             NumberFormatInfo.ValidateParseStyleFloatingPoint(style);
294             return Number.ParseSingle(s, style, NumberFormatInfo.GetInstance(provider));
295         }
296
297         public static Boolean TryParse(String s, out Single result)
298         {
299             if (s == null)
300             {
301                 result = 0;
302                 return false;
303             }
304
305             return TryParse((ReadOnlySpan<char>)s, NumberStyles.Float | NumberStyles.AllowThousands, NumberFormatInfo.CurrentInfo, out result);
306         }
307
308         public static bool TryParse(ReadOnlySpan<char> s, out float result)
309         {
310             return TryParse(s, NumberStyles.Float | NumberStyles.AllowThousands, NumberFormatInfo.CurrentInfo, out result);
311         }
312
313         public static Boolean TryParse(String s, NumberStyles style, IFormatProvider provider, out Single result)
314         {
315             NumberFormatInfo.ValidateParseStyleFloatingPoint(style);
316
317             if (s == null)
318             {
319                 result = 0;
320                 return false;
321             }
322
323             return TryParse((ReadOnlySpan<char>)s, style, NumberFormatInfo.GetInstance(provider), out result);
324         }
325
326         public static bool TryParse(ReadOnlySpan<char> s, NumberStyles style, IFormatProvider provider, out float result)
327         {
328             NumberFormatInfo.ValidateParseStyleFloatingPoint(style);
329             return TryParse(s, style, NumberFormatInfo.GetInstance(provider), out result);
330         }
331
332         private static Boolean TryParse(ReadOnlySpan<char> s, NumberStyles style, NumberFormatInfo info, out Single result)
333         {
334             bool success = Number.TryParseSingle(s, style, info, out result);
335             if (!success)
336             {
337                 ReadOnlySpan<char> sTrim = s.Trim();
338                 if (sTrim.EqualsOrdinal(info.PositiveInfinitySymbol))
339                 {
340                     result = PositiveInfinity;
341                 }
342                 else if (sTrim.EqualsOrdinal(info.NegativeInfinitySymbol))
343                 {
344                     result = NegativeInfinity;
345                 }
346                 else if (sTrim.EqualsOrdinal(info.NaNSymbol))
347                 {
348                     result = NaN;
349                 }
350                 else
351                 {
352                     return false; // We really failed
353                 }
354             }
355             return true;
356         }
357
358         //
359         // IConvertible implementation
360         //
361
362         public TypeCode GetTypeCode()
363         {
364             return TypeCode.Single;
365         }
366
367
368         bool IConvertible.ToBoolean(IFormatProvider provider)
369         {
370             return Convert.ToBoolean(m_value);
371         }
372
373         char IConvertible.ToChar(IFormatProvider provider)
374         {
375             throw new InvalidCastException(SR.Format(SR.InvalidCast_FromTo, "Single", "Char"));
376         }
377
378         sbyte IConvertible.ToSByte(IFormatProvider provider)
379         {
380             return Convert.ToSByte(m_value);
381         }
382
383         byte IConvertible.ToByte(IFormatProvider provider)
384         {
385             return Convert.ToByte(m_value);
386         }
387
388         short IConvertible.ToInt16(IFormatProvider provider)
389         {
390             return Convert.ToInt16(m_value);
391         }
392
393         ushort IConvertible.ToUInt16(IFormatProvider provider)
394         {
395             return Convert.ToUInt16(m_value);
396         }
397
398         int IConvertible.ToInt32(IFormatProvider provider)
399         {
400             return Convert.ToInt32(m_value);
401         }
402
403         uint IConvertible.ToUInt32(IFormatProvider provider)
404         {
405             return Convert.ToUInt32(m_value);
406         }
407
408         long IConvertible.ToInt64(IFormatProvider provider)
409         {
410             return Convert.ToInt64(m_value);
411         }
412
413         ulong IConvertible.ToUInt64(IFormatProvider provider)
414         {
415             return Convert.ToUInt64(m_value);
416         }
417
418         float IConvertible.ToSingle(IFormatProvider provider)
419         {
420             return m_value;
421         }
422
423         double IConvertible.ToDouble(IFormatProvider provider)
424         {
425             return Convert.ToDouble(m_value);
426         }
427
428         Decimal IConvertible.ToDecimal(IFormatProvider provider)
429         {
430             return Convert.ToDecimal(m_value);
431         }
432
433         DateTime IConvertible.ToDateTime(IFormatProvider provider)
434         {
435             throw new InvalidCastException(SR.Format(SR.InvalidCast_FromTo, "Single", "DateTime"));
436         }
437
438         Object IConvertible.ToType(Type type, IFormatProvider provider)
439         {
440             return Convert.DefaultToType((IConvertible)this, type, provider);
441         }
442     }
443 }