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());
}
}
Related
When the int variable is more than 10 digits, an error occurs and the number becomes negative.
Why is this happening and how can I solve the problem?
This is my code:
UnityWebRequest www = new UnityWebRequest("https://api.hypixel.net/skyblock/bazaar");
www.downloadHandler = new DownloadHandlerBuffer();
yield return www.SendWebRequest();
JSONNode itemsData = JSON.Parse(www.downloadHandler.text);
unixtimeOnline = itemsData2["lastUpdated"];
Debug.Log(unixtimeOnline);
// output -2147483648
tl;dr
Simply use ulong instead of int for unixtimeOnline
ulong unixtimeOnline = itemsData2["lastUpdated"];
What happened?
As was already mentioned int (or also System.Int32) has 32 bits.
The int.MaxValue is
2147483647
no int can be higher than that. What you get is basically a byte overflow.
From the JSON.Parse I suspect you are using SimpleJson
and if you have
int unixtimeOnline = itemsData2["lastUpdated"];
it will implicitly use
public static implicit operator int(JSONNode d)
{
return (d == null) ? 0 : d.AsInt;
}
which uses AsInt
public virtual int AsInt
{
get { return (int)AsDouble; }
set { AsDouble = value; }
}
which is a problem because a double can hold up to
so when you simply do
double d = 2147483648.0;
int example = (int)d;
you will again get
-2147483648
What you want
You want to use a type that supports larger numbers. Like e.g.
long: goes up to
9,223,372,036,854,775,807
and is actually what system time ticks are usually stored as (see e.g. DateTime.Ticks
or actually since your time is probably never negative anyway directly use the unsigned ones
ulong: goes up to
18,446,744,073,709,551,615
Solution
Long store short: There are implicit conversion for the other numeric values so all you need to do is use
ulong unixtimeOnline = itemsData2["lastUpdated"];
and it will use AsUlong instead
public static implicit operator ulong(JSONNode d)
{
return (d == null) ? 0 : d.AsULong;
}
which now correctly uses
public virtual ulong AsULong
{
get
{
ulong val = 0;
if (ulong.TryParse(Value, out val))
return val;
return 0;
}
set
{
Value = value.ToString();
}
}
As the comment says you will need to use a long variable type
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
I use ReShaper and when I compare two double values with ==, it suggests that I should use the Math. ABS method with a tolerance. See: https://www.jetbrains.com/help/resharper/2016.2/CompareOfFloatsByEqualityOperator.html
This example
double d = 0.0;
double d2 = 0.0;
if (d == d2)
{
/* some code */
}
is then converted to
double d = 0.0;
double d2 = 0.0;
if (Math.Abs(d - d2) < TOLERANCE)
{
/* some code */
}
But I think it's really complicated for a developer to think about the right tolerance. So I thought this may be implemented in the Double.Equals() method.
But this method is implemented like so
public override bool Equals(Object obj) {
if (!(obj is Double)) {
return false;
}
double temp = ((Double)obj).m_value;
// This code below is written this way for performance reasons i.e the != and == check is intentional.
if (temp == m_value) {
return true;
}
return IsNaN(temp) && IsNaN(m_value);
}
public bool Equals(Double obj)
{
if (obj == m_value) {
return true;
}
return IsNaN(obj) && IsNaN(m_value);
}
Why is that? And what is the correct way to compare double values?
You could create an extension method
public static class DoubleExtension
{
public static bool AlmostEqualTo(this double value1, double value2)
{
return Math.Abs(value1 - value2) < 0.0000001;
}
}
And use it like this
doubleValue.AlmostEqualTo(doubleValue2)
https://learn.microsoft.com/en-us/dotnet/api/system.numerics.complex.equals?view=net-6.0
If the obj parameter is not a Complex object, but it is a data type
for which an implicit conversion is defined, the Equals(Object) method
converts obj to a Complex object whose real part is equal to the value
of obj and whose imaginary part is equal to zero before it performs
the comparison. The following example illustrates this by finding that
a complex number and a double-precision floating-point value are
equal.
double n1 = 16.33;
System.Numerics.Complex c1 =
new System.Numerics.Complex(16.33, 0);
Console.WriteLine(c1.Equals(n1)); // Returns true.
I ended up using
double piConstant = 3.142;
double piFractional = 7/22;
if(piConstatnt.String("{0:0.00}")==piFractional.String("{0:0.00}")
{
// some code
}
This lets me control the precision by setting the desired string format.
https://www.csharp-examples.net/string-format-double/
In case you want more info on Equals method from microsoft.
https://learn.microsoft.com/en-us/dotnet/api/system.double.equals?view=net-5.0
For example, does an operator exist to handle this?
float Result, Number1, Number2;
Number1 = 2;
Number2 = 2;
Result = Number1 (operator) Number2;
In the past the ^ operator has served as an exponential operator in other languages, but in C# it is a bit-wise operator.
Do I have to write a loop or include another namespace to handle exponential operations? If so, how do I handle exponential operations using non-integers?
The C# language doesn't have a power operator. However, the .NET Framework offers the Math.Pow method:
Returns a specified number raised to the specified power.
So your example would look like this:
float Result, Number1, Number2;
Number1 = 2;
Number2 = 2;
Result = Math.Pow(Number1, Number2);
I stumbled on this post looking to use scientific notation in my code, I used
4.95*Math.Pow(10,-10);
But afterwards I found out you can do
4.95E-10;
Just thought I would add this for anyone in a similar situation that I was in.
There is a blog post on MSDN about why an exponent operator does NOT exists from the C# team.
It would be possible to add a power
operator to the language, but
performing this operation is a fairly
rare thing to do in most programs, and
it doesn't seem justified to add an
operator when calling Math.Pow() is
simple.
You asked:
Do I have to write a loop or include
another namespace to handle
exponential operations? If so, how do
I handle exponential operations using
non-integers?
Math.Pow supports double parameters so there is no need for you to write your own.
The lack of an exponential operator for C# was a big annoyance for us when looking for a new language to convert our calculation software to from the good ol' vb6.
I'm glad we went with C# but it still annoys me whenever I'm writing a complex equation including exponents. The Math.Pow() method makes equations quite hard to read IMO.
Our solution was to create a special DoubleX class where we override the ^-operator (see below)
This works fairly well as long as you declare at least one of the variables as DoubleX:
DoubleX a = 2;
DoubleX b = 3;
Console.WriteLine($"a = {a}, b = {b}, a^b = {a ^ b}");
or use an explicit converter on standard doubles:
double c = 2;
double d = 3;
Console.WriteLine($"c = {c}, d = {d}, c^d = {c ^ (DoubleX)d}"); // Need explicit converter
One problem with this method though is that the exponent is calculated in the wrong order compared to other operators. This can be avoided by always putting an extra ( ) around the operation which again makes it a bit harder to read the equations:
DoubleX a = 2;
DoubleX b = 3;
Console.WriteLine($"a = {a}, b = {b}, 3+a^b = {3 + a ^ b}"); // Wrong result
Console.WriteLine($"a = {a}, b = {b}, 3+a^b = {3 + (a ^ b)}"); // Correct result
I hope this can be of help to others who uses a lot of complex equations in their code, and maybe someone even has an idea of how to improve this method?!
DoubleX class:
using System;
namespace ExponentialOperator
{
/// <summary>
/// Double class that uses ^ as exponential operator
/// </summary>
public class DoubleX
{
#region ---------------- Fields ----------------
private readonly double _value;
#endregion ------------- Fields ----------------
#region -------------- Properties --------------
public double Value
{
get { return _value; }
}
#endregion ----------- Properties --------------
#region ------------- Constructors -------------
public DoubleX(double value)
{
_value = value;
}
public DoubleX(int value)
{
_value = Convert.ToDouble(value);
}
#endregion ---------- Constructors -------------
#region --------------- Methods ----------------
public override string ToString()
{
return _value.ToString();
}
#endregion ------------ Methods ----------------
#region -------------- Operators ---------------
// Change the ^ operator to be used for exponents.
public static DoubleX operator ^(DoubleX value, DoubleX exponent)
{
return Math.Pow(value, exponent);
}
public static DoubleX operator ^(DoubleX value, double exponent)
{
return Math.Pow(value, exponent);
}
public static DoubleX operator ^(double value, DoubleX exponent)
{
return Math.Pow(value, exponent);
}
public static DoubleX operator ^(DoubleX value, int exponent)
{
return Math.Pow(value, exponent);
}
#endregion ----------- Operators ---------------
#region -------------- Converters --------------
// Allow implicit convertion
public static implicit operator DoubleX(double value)
{
return new DoubleX(value);
}
public static implicit operator DoubleX(int value)
{
return new DoubleX(value);
}
public static implicit operator Double(DoubleX value)
{
return value._value;
}
#endregion ----------- Converters --------------
}
}
Since no-one has yet wrote a function to do this with two integers, here's one way:
private static long CalculatePower(int number, int powerOf)
{
long result = number;
for (int i = 2; i <= powerOf; i++)
result *= number;
return result;
}
Alternatively in VB.NET:
Private Function CalculatePower(ByVal number As Integer, ByVal powerOf As Integer) As Long
Dim result As Long = number
For i As Integer = 2 To powerOf
result = result * number
Next
Return result
End Function
CalculatePower(5, 3) ' 125
CalculatePower(8, 4) ' 4096
CalculatePower(6, 2) ' 36
For what it's worth I do miss the ^ operator when raising a power of 2 to define a binary constant. Can't use Math.Pow() there, but shifting an unsigned int of 1 to the left by the exponent's value works. When I needed to define a constant of (2^24)-1:
public static int Phase_count = 24;
public static uint PatternDecimal_Max = ((uint)1 << Phase_count) - 1;
Remember the types must be (uint) << (int).
I'm surprised no one has mentioned this, but for the simple (and probably most encountered) case of squaring, you just multiply by itself.
float someNumber;
float result = someNumber * someNumber;
A good power function would be
public long Power(int number, int power) {
if (number == 0) return 0;
long t = number;
int e = power;
int result = 1;
for(i=0; i<sizeof(int); i++) {
if (e & 1 == 1) result *= t;
e >>= 1;
if (e==0) break;
t = t * t;
}
}
The Math.Pow function uses the processor power function and is more efficient.
It's no operator but you can write your own extension function.
public static double Pow(this double value, double exponent)
{
return Math.Pow(value, exponent);
}
This allows you to write
a.Pow(b);
instead of
Math.Pow(a, b);
I think that makes the relation between a and b a bit clearer + you avoid writing 'Math' over and over again.
Is it posible to create a method with a decimal argument, that only accepts values from 0 to 1?
Example:
public decimal GetSamplingError(decimal percent){
decimal result = 0;
result = 100*percent;
return result;
}
is it posible to control that the parameter percent is compres between 0 and 1?
Thanks and sorry for my bad english.
no there is no way to control parameter's range, what you can do, is control it inside the function itself, and add a comment to the function
public decimal GetSamplingError(decimal percent){
if(percent > 1)
percent = 1;
else if(percent <0)
percent = 0;
return 100*percent;
}
Or raise an ArgumentOutOfRangeException in case if the parameter is not in dsired range, but it depends on how you would like to manage a worklfow of your application.
I would create my own type of Percent with range checks as others have suggested and some additional stuff. That way, Percent is its own entity in your application and everyone knows when and how to use it. A plain decimal might work as well, I prefer the typed approach however.
internal class Percent
{
private readonly decimal _value;
public decimal Value
{
get { return _value; }
}
public Percent(decimal value)
{
_value = (100 * value);
if (value < 0m || value > 1m)
{
throw new ArgumentOutOfRangeException("value");
}
}
public override string ToString()
{
return String.Format("{0}%", _value);
}
public override int GetHashCode()
{
// HashCode implementation;
}
public override bool Equals(object obj)
{
// Equals implementation;
}
}
There is no way of compile-time checking this. The best solution would be to check the argument at run-time:
public decimal GetSamplingError(decimal percent)
{
if (percent < 0m || percent > 1m)
{
throw new ArgumentException("Percent should be between 0 and 1!", "percent");
}
decimal result = 0;
result = 100*percent;
return result;
}
Other than the approach of Tigran, this will throw an Exception when an invalid argument is passed. I prefer this method over just changing the percent-value, becasue it'll actually make you notice that you passed a wrong value.
When you use Code Contracts of Microsoft, then you could add a contract that ensures that the value is in a specific range. When static checking is enabled, you'll get an error message at compile-time.
Contract.Requires(percent > 0m && percent < 1m, "Percent must be between 0 and 1");
You would have to do:
public decimal GetSamplingError(decimal percent){
if (percent < 0m || percent > 1m)
throw new ArgumentOutOfRangeException("percent", "Must be between 0 and 1.");
// rest of method
}
Of course, it is also possible to make your own struct called DecimalBetweenZeroAndOne which is immutable and holds a decimal field which is readonly and where you write a check to guarantee that the value of the field is always in the required range.
It is possible to validate the input and throw exception if value is not what you expected:
decimal getPercentage(decimal val)
{
if (val < 0 || val > 1)
throw new ArgumentException();
return val * 100;
}