I'm working on an importer for LitJson, to import float values from ints, and doubles, and if overflow-checking is enabled, I want to wrap a potential overflow exception in a JsonException with a bit more information about the failure.
Right now my code looks like this, and I don't know if I need to/can check if the context is checked or not:
private static float DoubleFloatImporter(double value) {
try
{
return (float)value;
}
catch (Exception ex)
{
throw new JsonException("Value is not a valid Single", ex);
}
}
You may be thinking of checked and unchecked contexts, but these are not relevant for your example, the explicit conversion (cast) from double to float (so from double-precision binary floating point to single-precision).
A finite double value may round to an infinite float value (either float.PositiveInfinity or float.NegativeInfinity).
For example DoubleFloatImporter(1.23e123). As a double, the input 1.23e123 will be represented as a finite value, but when cast to float, the nearest representable value will be interpreted as +∞.
Edit: As I say in comments, something like:
private static float DoubleFloatImporter(double value) {
var converted = (float)value;
if (!float.IsFinite(converted))
throw new JsonException("Converted value would become infinite or not a number");
return converted;
}
may suit your need.
What about something like this:
static float DoubleFloatImporter(double value)
{
if (double.IsPositiveInfinity(value))
{
return float.PositiveInfinity;
}
if (double.IsNegativeInfinity(value))
{
return float.NegativeInfinity;
}
if (value > Single.MaxValue || value < Single.MinValue)
{
throw new OverflowException($"'{value}' doesn't fit");
}
return (float)value; //Single.CreateChecked(value);
}
Some examples:
using System.Runtime.CompilerServices;
Convert(1.0);
Convert(double.MaxValue);
Convert(double.PositiveInfinity);
Convert(double.NegativeInfinity);
Convert((double)float.MaxValue + 100);
Convert((double)float.MaxValue * 2);
Convert(double.NaN);
static void Convert(double v, [CallerArgumentExpression("v")] string arg1Exp = "?")
{
try
{
var f = DoubleFloatImporter(v);
Console.WriteLine($"{arg1Exp} -> {f}");
}
catch (Exception ex)
{
Console.WriteLine($"{arg1Exp} -> {ex.Message}");
}
}
The output:
1.0 -> 1
double.MaxValue -> '1.7976931348623157E+308' doesn't fit
double.PositiveInfinity -> ∞
double.NegativeInfinity -> -∞
(double)float.MaxValue + 100 -> 3.4028235E+38
(double)float.MaxValue * 2 -> '6.805646932770577E+38' doesn't fit
double.NaN -> NaN
Related
I wrote this function:
public static float parseFloat(string number)
{
float ishod = 0;
try
{
float.TryParse(number.Replace(".", ","), out ishod);
}
catch(Exception ex)
{
ishod = -1;
Console.WriteLine("parseFloat(): " + ex.Message);
}
return ishod;
}
because when entering float numbers like 4.5 in console application, it doesn't see the dot so it glues the two numbers. I get 45.
Though it will work, it is dubious when you pass 0 or -1 since you don't know if it produces error or a proper result.
I was wondering, does float type in C# has some number constant that represents an error state, so that I can return it and be sure something failed?
On the other hand what would be an error constant for integer in C#?
Or I should rethink my function and make it differently?
Well, floating point values have two kind of separators: decimal and thousand, e.g.
123,456,789.12
When parsing, thousand separators are ignored while decimal is turned into decimal point: "123,456,789.12" -> 123456789.12.
Please, note, that both separators are culture specific:
"123.456.789,12" // Russian Culture, "ru-RU" - comma is a decimal separator
"123,456,789.12" // English Culture "en-US" - dot is a decimal separator
In your case, you want to treat '.' as a decimal separtor, that's why let's parse it with Invariant Culture (your current culture treats '.' as a thousand separator and ignores it: "1.2" -> 12):
using System.Globalization;
...
public static float parseFloat(string number) {
// float.TryParse doesn't throw exceptions but returns true or false
if (float.TryParse(number,
NumberStyles.Any,
CultureInfo.InvariantCulture,
out float result))
return result;
else {
Console.WriteLine("Invalid floating point value.");
// Not A Number
return float.NaN;
}
}
Possible usage:
float value;
do {
Console.Write("Enter the value, please: ");
// Keep asking user
value = parseFloat(Console.ReadLine());
}
while (float.IsNaN(value)); // while the input provided is invalid
The TryParse method will not throw an exception in case of failure, it will simply return false. This makes your method redundant - you can simply do:
if(float.TryParse(someStringValue, out float ishod))
{
// success
}
else
{
Console.WriteLine("failed to parse {0} to float.", someStringValue);
}
If you really want to return a float whatever the conversion makes then you can return NaN when you are sure:
public static float parseFloat(string number)
{
float ishod = 0;
try
{
float.TryParse(number.Replace(".", ","), out ishod);
}
catch(Exception ex)
{
ishod = float.NaN;
Console.WriteLine("parseFloat(): " + ex.Message);
}
return ishod;
}
I created a validation function as below:
public static T getAsDigit<T>( this Textbox tb, float min, float max ){
}
Most of the time, the validation range is specificed in integers. It works fine. But when I try to pass in decimals, it give me error sth like can't convert double to float, I have to change defination to double.
I am new to C#, how can I pass in the digits as float ? without doing sth unintuitive like Convert.toFloat('1.3').
My use case only requires 3 decimal place precision, value range 0.000 ~ 10.000. Is there any disadvantage in using float versus double in C#? Since I used and saw people use float a lot in sql when decimal() is optional.
Use f literal: getAsDigit(1.34f)
Or cast value to float getAsDigit((float)1.34)
You have to convert the double to flow so i recommend you do
float.Parse(x)
the cleaner option would be to create a new var and convert it to float there instead of in the injection so something like this:
double x = 1.3;
var newFloat = float.Parse(x);
I think you want to write a validation for the value of the TextBox.
You can upgrade your method to make it generic for all value type struct
public static T getAsDigit<T>(this TextBox tb, T min, T max) where T : struct, IComparable<T>
{
var valueConverted = default(T);
try
{
valueConverted = (T)Convert.ChangeType(tb.Text, typeof(T));
}
catch(Exception e)
{
//do something you want, rethown i.e
}
if (valueConverted.CompareTo(max) > 0)
return max;
if (valueConverted.CompareTo(min) < 0)
return min;
return valueConverted;
}
And you can simply pass the type you want.
string a = "10.5"; // suppose that a is TextBox.Text
var b = a.getAsDigit<float>(10,11); // return 10.5f
var c = a.getAsDigit<decimal>(11,12); //return 11d
var d = a.getAsDigit<double>(9,10); //return 10d
Every time we need a high decimal-precision, we use decimals to do the calculations. Is there any way to check if the precision did suffice for the calculation?
I would like to make the following code throw an exception:
decimal almostMax = Decimal.MaxValue - 1;
decimal x = almostMax + 0.1m; // This should create an exception, since x equals almostMax.
Assert.AreEqual(x, almostMax); // This does NOT fail.
It doesn't really matter in real code, but it would be nice to be safe.
This extension method should help. It reverses the operation and checks if the input arguments can be calculated correctly from the result. If that's not the case then the operation caused precision loss.
public static decimal Add(this decimal a, decimal b)
{
var result = a + b;
if (result - a != b || result - b != a)
throw new InvalidOperationException("Precision loss!");
return result;
}
Working example: https://dotnetfiddle.net/vx6UYY
If you want to use the regular operators like + etc, you have to go with Philipp Schmid's solution and implement the operators on your own decimal type.
You could make a SaveDecimal class and overload the + operator
https://msdn.microsoft.com/en-us/library/aa288467%28v=vs.71%29.aspx
public class SafeDecimal
{
private decimal DecValue;
public SafeDecimal(decimal Value)
{
DecValue = Value;
}
public decimal GetValue()
{
return DecValue;
}
public static SafeDecimal operator +(SafeDecimal A, SafeDecimal B)
{
decimal almostMax = Decimal.MaxValue - 1;
checked
{
if (almostMax <= A.GetValue() + B.GetValue())
throw new Exception("----scary error message----");
}
return new SafeDecimal(A.GetValue() + B.GetValue());
}
}
While writing a plugin for Autocad (drawing software) i create a 3d point build upout of 3 double values representing the X, the Y and the Z value for a point in 3d.
Point3d insertPoint = new Point3d((insPointX = StrToDouble(tbInsPointX.Text)),
insPointY = StrToDouble(tbInsPointY.Text),
insPointZ = StrToDouble(tbInsPointZ.Text));
and the StrToDouble looks like this:
public double StrToDouble(string str)
{
double x = 0;
try
{
x = double.Parse(str.Replace(",", "."));
}
catch (System.Exception ex) { MessageBox.Show(ex.Message); }
return x;
}
But now its actually always returning an double, as when the parse fails it returns the double as 0.
I am wondering now what would be the right way to report back to the 3dpoint creation that there was an error and it should no longer continue.
I can think of using a bool or something, but i think it might not be a nice clean way to do this. As im only a hobby programmer im not sure what the right way is to do this.
Letting it stop when the double = 0 is not an option as it can actually be a real value.
You're probably looking for double.TryParse, which has the added advantage that it doesn't throw exceptions.
double output;
if (double.TryParse(input, out output))
{
// Success
}
else
{
// Failure
}
Pretty much all 'struct' types in .NET (numbers, DateTime, TimeSpan, etc) have a TryParse method, if you're every looking for similar functionality.
To answer your follow up, you could wrap the parsing of a Point3d into a similar TryParse method:
private static bool TryParsePoint3d(string x, string y, string z, out Point3d output)
{
double xValue, yValue, zValue;
if (double.TryParse(x, out xValue) &&
double.TryParse(y, out yValue) &&
double.TryParse(z, out zValue))
{
output = new Point3d(xValue, yValue, zValue);
return true;
}
// out params must be assigned, use null if it's a class
output = new Point3d();
return false;
}
Which you can use as
Point3d insertPoint;
if (TryParsePoint3d(tbInsPointX.Text, tbInsPointY.Text, tbInsPointZ.Text,
out insertPoint))
{
insertPoint is safe to use
}
Using C#, I have a few custom classes where I need to be able to detect integer overflows and return a default minimum or maximum value depending on if the overflow was due to the result being over the maximum value or under the minimum value. I can't seem to find a suggestion on how to detect the "type" of overflow that occurs anywhere.
The classes are divided between two general types: ones that use signed values, and ones that use unsigned values.
As an example, here is one of the classes that deals with Int32 values:
public class Stat32Tf : IStat32T<float>
{
#region fields
private int baseValue, baseAdjustment;
private float baseMultiplier;
#endregion
#region ctors
public Stat32Tf()
{
baseValue = 0;
baseAdjustment = 0;
baseMultiplier = 1f;
}
public Stat32Tf(int baseValue, int baseAdjustment = 0, float baseMultiplier = 1f)
{
this.baseValue = baseValue;
this.baseAdjustment = baseAdjustment;
this.baseMultiplier = baseMultiplier;
}
#endregion
#region properties
public int BaseValue
{
get
{
return baseValue;
}
set
{
baseValue = value;
}
}
public int BaseAdjustment
{
get
{
return baseAdjustment;
}
set
{
baseAdjustment = value;
}
}
public float BaseMultiplier
{
get
{
return BaseMultiplier;
}
set
{
baseMultiplier = value;
}
}
public int TruncValue
{
get
{
return (int)Value;
}
}
public float Value
{
get
{
return (baseValue + baseAdjustment) * baseMultiplier;
}
}
#endregion
}
As you can see, the idea of the class is to hold a base value, an adjustment value, and a multiplier value, and return the aggregate value in the Value property. (The TruncValue property just, as it suggests, returns the truncated whole value, dropping any fractional values).
The goal is to handle overflows in the "get" accessor of the Value property and, if the result is over the max int value, return int.MaxValue and if it is under the min value, return int.MinValue, all without throwing the actual overflow error. The part that's making it tricky for me is that the adjustment values and multipliers could be negative values as well (as per the design requirement).
What is a safe way to achieve this? I have not been able to find any resources that address this kind of situation. I'm guessing some sort of arithmetic algorithm will need to be used to determine of results will be over or under.
There are only a limited number of cases where it could underflow:
If baseValue and baseAdjustment are both negative -> If Int.MinValue - baseAdjustment > baseValue then you have an underflow.
If baseValue + baseAjustment is negative and baseMultiplier is positive -> If an overflow exception is raised, then it can only be an underflow.
If baseValue + baseAdjustment is positive but baseMultiplier is negative -> If an overflow exception is raised, then it can only be an underflow.
If you want to avoid raising/catching exception, then it might be a bit more complicated (you may want to cast the result as long and compare it against Int.MaxValue; that way it'll only raise an exception if the result goes over Long.MaxValue).
Floats are pretty big. Are you expecting the get value to overflow or do you expect the cast to int to overflow? If it's just the cast something similar to the following code might work.
//This answer is wrong, see below.
public int TruncValue
{
get
{
if (Value > (float)int.MaxValue)
{
return int.MaxValue
}
else if (Value < (float)int.MinValue)
{
return int.MinValue
}
else
{
return (int)Value;
}
}
}
Although you might need some additional handling for the edge cases.
Edit - I played around with this in some code and found some behavior that I didn't expect, but apparently it is in the specification.
For example,
var Value = int.MaxValue + int.MaxValue //Ends up returning -2 with no exception in debug mode.
var MaxCalculatedValue = (int.MaxValue + int.MaxValue) * float.MaxValue //Ends up returning something like -3.4... ^38.
You really might need to up cast everything into a double and then check to see if the result is greater than or less than an int.
So it might look something like this:
public float Value
{
get
{
var result = ((double)baseValue + (double)baseAdjustment) * (double)baseMultiplier;
if (result > (double)int.MaxValue)
{
return (float)int.MaxValue)
}
if (result < (double)int.MinValue)
{
return (float)int.MinValue)
}
return (float)result;
}
}