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.
5 /*============================================================
9 ** Purpose: A wrapper class for the primitive type float.
12 ===========================================================*/
14 using System.Globalization;
15 using System.Runtime.CompilerServices;
16 using System.Runtime.InteropServices;
17 using System.Runtime.Versioning;
19 using Internal.Runtime.CompilerServices;
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
28 private float m_value; // Do not rename (binary serialization)
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;
40 // We use this explicit definition to avoid the confusion between 0.0 and -0.0.
41 internal const float NegativeZero = (float)-0.0;
43 /// <summary>Determines whether the specified value is finite (zero, subnormal, or normal).</summary>
45 [MethodImpl(MethodImplOptions.AggressiveInlining)]
46 public static bool IsFinite(float f)
48 var bits = BitConverter.SingleToInt32Bits(f);
49 return (bits & 0x7FFFFFFF) < 0x7F800000;
52 /// <summary>Determines whether the specified value is infinite.</summary>
54 [MethodImpl(MethodImplOptions.AggressiveInlining)]
55 public static unsafe bool IsInfinity(float f)
57 var bits = BitConverter.SingleToInt32Bits(f);
58 return (bits & 0x7FFFFFFF) == 0x7F800000;
61 /// <summary>Determines whether the specified value is NaN.</summary>
63 [MethodImpl(MethodImplOptions.AggressiveInlining)]
64 public static unsafe bool IsNaN(float f)
66 var bits = BitConverter.SingleToInt32Bits(f);
67 return (bits & 0x7FFFFFFF) > 0x7F800000;
70 /// <summary>Determines whether the specified value is negative.</summary>
72 [MethodImpl(MethodImplOptions.AggressiveInlining)]
73 public static unsafe bool IsNegative(float f)
75 var bits = unchecked((uint)BitConverter.SingleToInt32Bits(f));
76 return (bits & 0x80000000) == 0x80000000;
79 /// <summary>Determines whether the specified value is negative infinity.</summary>
81 [MethodImpl(MethodImplOptions.AggressiveInlining)]
82 public static unsafe bool IsNegativeInfinity(float f)
84 return (f == float.NegativeInfinity);
87 /// <summary>Determines whether the specified value is normal.</summary>
89 // This is probably not worth inlining, it has branches and should be rarely called
90 public static unsafe bool IsNormal(float f)
92 var bits = BitConverter.SingleToInt32Bits(f);
94 return (bits < 0x7F800000) && (bits != 0) && ((bits & 0x7F800000) != 0);
97 /// <summary>Determines whether the specified value is positive infinity.</summary>
99 [MethodImpl(MethodImplOptions.AggressiveInlining)]
100 public static unsafe bool IsPositiveInfinity(float f)
102 return (f == float.PositiveInfinity);
105 /// <summary>Determines whether the specified value is subnormal.</summary>
107 // This is probably not worth inlining, it has branches and should be rarely called
108 public static unsafe bool IsSubnormal(float f)
110 var bits = BitConverter.SingleToInt32Bits(f);
112 return (bits < 0x7F800000) && (bits != 0) && ((bits & 0x7F800000) == 0);
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.
121 public int CompareTo(Object value)
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;
134 // At least one of the values is NaN.
136 return (IsNaN(f) ? 0 : -1);
140 throw new ArgumentException(SR.Arg_MustBeSingle);
144 public int CompareTo(Single value)
146 if (m_value < value) return -1;
147 if (m_value > value) return 1;
148 if (m_value == value) return 0;
150 // At least one of the values is NaN.
152 return (IsNaN(value) ? 0 : -1);
158 public static bool operator ==(Single left, Single right)
160 return left == right;
164 public static bool operator !=(Single left, Single right)
166 return left != right;
170 public static bool operator <(Single left, Single right)
176 public static bool operator >(Single left, Single right)
182 public static bool operator <=(Single left, Single right)
184 return left <= right;
188 public static bool operator >=(Single left, Single right)
190 return left >= right;
193 public override bool Equals(Object obj)
195 if (!(obj is Single))
199 float temp = ((Single)obj).m_value;
205 return IsNaN(temp) && IsNaN(m_value);
208 public bool Equals(Single obj)
215 return IsNaN(obj) && IsNaN(m_value);
218 public override int GetHashCode()
220 var bits = Unsafe.As<float, int>(ref m_value);
222 // Optimized check for IsNan() || IsZero()
223 if (((bits - 1) & 0x7FFFFFFF) >= 0x7F800000)
225 // Ensure that all NaNs and both zeros have the same hash code
232 public override String ToString()
234 return Number.FormatSingle(m_value, null, NumberFormatInfo.CurrentInfo);
237 public String ToString(IFormatProvider provider)
239 return Number.FormatSingle(m_value, null, NumberFormatInfo.GetInstance(provider));
242 public String ToString(String format)
244 return Number.FormatSingle(m_value, format, NumberFormatInfo.CurrentInfo);
247 public String ToString(String format, IFormatProvider provider)
249 return Number.FormatSingle(m_value, format, NumberFormatInfo.GetInstance(provider));
252 public bool TryFormat(Span<char> destination, out int charsWritten, ReadOnlySpan<char> format = default, IFormatProvider provider = null)
254 return Number.TryFormatSingle(m_value, format, NumberFormatInfo.GetInstance(provider), destination, out charsWritten);
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.
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.
265 public static float Parse(String s)
267 if (s == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.s);
268 return Number.ParseSingle(s, NumberStyles.Float | NumberStyles.AllowThousands, NumberFormatInfo.CurrentInfo);
271 public static float Parse(String s, NumberStyles style)
273 NumberFormatInfo.ValidateParseStyleFloatingPoint(style);
274 if (s == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.s);
275 return Number.ParseSingle(s, style, NumberFormatInfo.CurrentInfo);
278 public static float Parse(String s, IFormatProvider provider)
280 if (s == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.s);
281 return Number.ParseSingle(s, NumberStyles.Float | NumberStyles.AllowThousands, NumberFormatInfo.GetInstance(provider));
284 public static float Parse(String s, NumberStyles style, IFormatProvider provider)
286 NumberFormatInfo.ValidateParseStyleFloatingPoint(style);
287 if (s == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.s);
288 return Number.ParseSingle(s, style, NumberFormatInfo.GetInstance(provider));
291 public static float Parse(ReadOnlySpan<char> s, NumberStyles style = NumberStyles.Float | NumberStyles.AllowThousands, IFormatProvider provider = null)
293 NumberFormatInfo.ValidateParseStyleFloatingPoint(style);
294 return Number.ParseSingle(s, style, NumberFormatInfo.GetInstance(provider));
297 public static Boolean TryParse(String s, out Single result)
305 return TryParse((ReadOnlySpan<char>)s, NumberStyles.Float | NumberStyles.AllowThousands, NumberFormatInfo.CurrentInfo, out result);
308 public static bool TryParse(ReadOnlySpan<char> s, out float result)
310 return TryParse(s, NumberStyles.Float | NumberStyles.AllowThousands, NumberFormatInfo.CurrentInfo, out result);
313 public static Boolean TryParse(String s, NumberStyles style, IFormatProvider provider, out Single result)
315 NumberFormatInfo.ValidateParseStyleFloatingPoint(style);
323 return TryParse((ReadOnlySpan<char>)s, style, NumberFormatInfo.GetInstance(provider), out result);
326 public static bool TryParse(ReadOnlySpan<char> s, NumberStyles style, IFormatProvider provider, out float result)
328 NumberFormatInfo.ValidateParseStyleFloatingPoint(style);
329 return TryParse(s, style, NumberFormatInfo.GetInstance(provider), out result);
332 private static Boolean TryParse(ReadOnlySpan<char> s, NumberStyles style, NumberFormatInfo info, out Single result)
334 bool success = Number.TryParseSingle(s, style, info, out result);
337 ReadOnlySpan<char> sTrim = s.Trim();
338 if (sTrim.EqualsOrdinal(info.PositiveInfinitySymbol))
340 result = PositiveInfinity;
342 else if (sTrim.EqualsOrdinal(info.NegativeInfinitySymbol))
344 result = NegativeInfinity;
346 else if (sTrim.EqualsOrdinal(info.NaNSymbol))
352 return false; // We really failed
359 // IConvertible implementation
362 public TypeCode GetTypeCode()
364 return TypeCode.Single;
368 bool IConvertible.ToBoolean(IFormatProvider provider)
370 return Convert.ToBoolean(m_value);
373 char IConvertible.ToChar(IFormatProvider provider)
375 throw new InvalidCastException(SR.Format(SR.InvalidCast_FromTo, "Single", "Char"));
378 sbyte IConvertible.ToSByte(IFormatProvider provider)
380 return Convert.ToSByte(m_value);
383 byte IConvertible.ToByte(IFormatProvider provider)
385 return Convert.ToByte(m_value);
388 short IConvertible.ToInt16(IFormatProvider provider)
390 return Convert.ToInt16(m_value);
393 ushort IConvertible.ToUInt16(IFormatProvider provider)
395 return Convert.ToUInt16(m_value);
398 int IConvertible.ToInt32(IFormatProvider provider)
400 return Convert.ToInt32(m_value);
403 uint IConvertible.ToUInt32(IFormatProvider provider)
405 return Convert.ToUInt32(m_value);
408 long IConvertible.ToInt64(IFormatProvider provider)
410 return Convert.ToInt64(m_value);
413 ulong IConvertible.ToUInt64(IFormatProvider provider)
415 return Convert.ToUInt64(m_value);
418 float IConvertible.ToSingle(IFormatProvider provider)
423 double IConvertible.ToDouble(IFormatProvider provider)
425 return Convert.ToDouble(m_value);
428 Decimal IConvertible.ToDecimal(IFormatProvider provider)
430 return Convert.ToDecimal(m_value);
433 DateTime IConvertible.ToDateTime(IFormatProvider provider)
435 throw new InvalidCastException(SR.Format(SR.InvalidCast_FromTo, "Single", "DateTime"));
438 Object IConvertible.ToType(Type type, IFormatProvider provider)
440 return Convert.DefaultToType((IConvertible)this, type, provider);