Example:
public static double ComputeFoo(double nom, double den, double epsilon = 2.2e-16)
{
double den1 = den == 0.0 ? epsilon : den;
// den1 can still be zero if epsilon is zero
// is there any way to retrieve 2.2e-16 here and assign it to den1?
return nom/den1;
}
Is there a way to retrieve 2.2e-16 value and use it in method?
P.S.: I understand that for this particular example I can just call ComputeFoo(nom, den1).
You can set a constant value somewhere in your class, and pass it as the default value to the method. Once there you can check if the passed value is different from the constant or viceversa:
static void Main(string[] args)
{
Test(0);
}
const int constantValue = 15;
static int Test(int testValue = constantValue)
{
Console.WriteLine(testValue);
Console.WriteLine(constantValue);
return constantValue;
}
Note: constantValue must be a constant in order to build successfuly.
Here's a different approach I mentioned above in my comment using Reflection; generic approach.
public static T GetDefaultOptionalParamValue<T, TClass>(string methodName, string paramName)
{
if (typeof(TClass).GetMethod(methodName)?.GetParameters().Where(p => p.Attributes.HasFlag(ParameterAttributes.Optional) &&
p.Attributes.HasFlag(ParameterAttributes.HasDefault) && p.Name == paramName)?.FirstOrDefault()?.DefaultValue is T myValue)
{
return myValue;
}
else { return default; }
}
You can this call it like so:
var t = GetDefaultOptionalParamValue<double, ClassName>("ComputeFoo", "epsilon");
t value is 2.2E-16
Use reflection in System.Diagnostics to get access to the parameters. This will get the default value of the third parameter of the enclosing function:
var x = new StackFrame(0).GetMethod().GetParameters()[2].DefaultValue;
It's not possible to get the default value just from the method. A way this might work for you is making the default value a constant in your class. For example:
private const double epsilonDefault = 2.2e-16;
public static double ComputeFoo(double nom, double den, double epsilon = epsilonDefault)
{
double den1 = den == 0.0 ? epsilon : den;
if (den1 == 0) den1 = epsilonDefault;
return nom / den1;
}
This way your default value is declared outside the method and available when you need it.
EDIT: To be complete, through reflection it is possible to do this but this seems too much for this question. An basic example of how to do this with reflection:
public static void Execute(int number = 10)
{
Console.WriteLine(number);
var defaultValue = typeof(Program)
.GetMethod("Execute")
.GetParameters()[0]
.DefaultValue;
Console.WriteLine(defaultValue); // 10
}
NO, you can't. The only default value that can be set is null
public static double ComputeFoo(double nom, double den, double ?epsilon )
{
if (epsilon == null)
epsilon = 2.2e-16
double den1 = den == 0.0 ? epsilon : den;
// den1 can still be zero if epsilon is zero
// is there any way to retrieve 2.2e-16 here and assign it to den1?
return nom/den1;
}
Related
I want to return an object as the result of a calculation in a method but I get "Cannot implicitly convert type 'ConsoleApp2Iteration.LoanOut' to 'double". The "return new LoanOut" is underlined. What is going wrong? I need the three outputs (InterestPaymentAnnual etc.) as input to other calculations elsewhere.
public class Loan
{
> initialisers here
public double LoanCalc()
{
double nper = LoanYrs * NprPrYr;//payment terms per yr
`double EffectiveRate = Math.Pow(1 + (InterestPct + ContribPct),
(Math.Pow(NprPrYr, -1))) - 1;`
//interest per payment term
double Interest_Contribution = InterestPct + ContribPct;
double length = nper;
double InterestPaymentP1 = 0;
{
Pymnt = Financial.Pmt(EffectiveRate, nper, LoanNPV, 0, 0);
LoanOutstanding = LoanNPV;
for (int i = 1; i <= length; i++)
{
// code block removed for clarity
if (i % NprPrYr != 0)
// testing for full years as derived calculations use input inyears
{
InterestPaymentAnnual += Interest_ContributionUSD;
RePymntAnnual += RePymnt;
}
else
{
InterestPaymentAnnual += Interest_ContributionUSD;
RePymntAnnual += RePymnt;
// new object which containts annual interest payment, annual repayment and
// remaining loan amount
return new LoanOut(InterestPaymentAnnual, RePymntAnnual,
LoanOutstanding);
//initialisation before new payment cycle
InterestPaymentAnnual = 0;
RePymntAnnual = 0;
}
}
}
return InterestPymntP1;
}
}
public class LoanOut
{
public double InterestPaymentAnnual { get; private set; }
public double RePymntAnnual { get; private set; }
public double LoanOutstanding { get; private set; }
double InterestPymntP1 = 0;
double Repayment = 0;
double DebtRemaining = 0;
public LoanOut(double InterestPaymentAnnual, double RePymntAnnual,
double LoanOutstanding)
{
this.InterestPaymentAnnual = InterestPymntP1;
this.RePymntAnnual = Repayment;
this.LoanOutstanding = DebtRemaining;
}
}
Your method is declared as returning a double and you have a statement
return new LoanOut(InterestPaymentAnnual, RePymntAnnual, LoanOutstanding);
Change the return type of your method to LoanOut:
public LoanOut LoanCalc()
As others have stated, you are trying to return both a LoanOut instance, and a double.
return new LoanOut(InterestPaymentAnnual, RePymntAnnual, LoanOutstanding); //Returning LoanOut Instance
and
return InterestPymntP1; //Returning double
if you need (or want) to gain two values from a method call, you should look at out parameters.
EG.
public LoanOut LoanCalc(out double InterestPayment)
{
//Your stuff here
}
You have to assign to InterestPayment for the calling code to use it.
Alternatively you can change your LoanOut class to also contain your 'InterestPayment' informaiton on that object. You would only NOT do that if the InterestPayment info doesn't relate to the LoanOut instance... which looking at it probably isn't the case.
Also, if you do fix this and keep the method structured as displayed in your question, You have unreachable code directly after the return new LoanOut line...
InterestPaymentAnnual = 0;
RePymntAnnual = 0;
will never get run
You have method public double LoanCalc() but you try to return new LoanOut(). So the error is correct, you can't convert LoanOut to double. Change the method signature to return LoanOut.
Also, if the pasted code formatting is what you have in your editor I would strongly suggest to reformat your code to make it more readable.
If i'm reading this right, you want to return a LoanOut but you're getting the error that you are trying to convert from LoanOut to double. Your method, however specifically says that you'll be returning a double:
public double LoanCalc()
I would try replacing double with LoanOut like this:
public LoanOut LoanCalc()
Does that help?
i want to compare thickness, by checking if
Thickness A equals thickness B,
And.. it dont work. Always false, why?
ps.
Why new Thickness(2.1) returns 2.09923289[..] not 2.1
and new Thickness(2.0) returns clear 2.0?
Double values are not safe to compare, because of how double are stored in memory. I would advise you to use something like if(Math.Abs(Thickness - new Thickness(2.1)) < TOLERANCE).
You can do a quick test and try to check something like:
var passed = false;
if(0.2 + 0.1 == 0.3)
passed = true;
And you'll see that it is false
The values for the left, top, right and bottom of a Thickness are double values.
As such, you have to use Math.Abs to compare them against a tolerance value.
These are the helper methods I've got in my WinUX library which will do the job for you:
public static readonly double Epsilon = 2.2204460492503131E-16;
public static bool AreClose(Thickness value1, Thickness value2)
{
return AreClose(value1.Left, value2.Left) && AreClose(value1.Top, value2.Top) && AreClose(value1.Right, value2.Right) && AreClose(value1.Bottom, value2.Bottom);
}
public static bool AreClose(double value1, double value2)
{
if (Math.Abs(value1 - value2) < 0.00005)
{
return true;
}
var a = (Math.Abs(value1) + Math.Abs(value2) + 10.0) * Epsilon;
var b = value1 - value2;
return (-a < b) && (a > b);
}
You'd then use it in your scenario like this:
if (AreClose(new Thickness(2.1), lessonGrid.BorderThickness))
{
// Code-here
}
Original source: https://github.com/jamesmcroft/WinUX-UWP-Toolkit/blob/develop/WinUX/WinUX.Common/Maths/MathHelper.cs
We are using one code analyzer which has a rule like this "Do Not Check Floating Point Equality/Inequality".Below is the example given.
float f = 0.100000001f; // 0.1
double d = 0.10000000000000001; // 0.1
float myNumber = 3.146f;
if ( myNumber == 3.146f ) //Noncompliant. Because of floating point imprecision, this will be false
{
////
}
else
{
////
}
if (myNumber <= 3.146f && mNumber >= 3.146f) // Noncompliant indirect equality test
{
// ...
}
if (myNumber < 4 || myNumber > 4) // Noncompliant indirect inequality test
{
// ...
}
when I tested this code if ( myNumber == 3.146f ) is true so I am not able to understand what this rule is trying to say.
What is solution or code change required for this rule?
Is this rule applicable for C#? When I googled I see more examples of C/C++ for this rule
Floating point is not precise. In some cases, the result is unexpected, so it's bad practice to compare floating point number for equality without some tolerance.
It can be demonstrated with simple example.
if(0.1 + 0.2 == 0.3)
{
Console.WriteLine("Equal");
}
else
{
Console.WriteLine("Not Equal");
}
It will print Not Equal.
Demo: https://dotnetfiddle.net/ltAFWe
The solution is to add some tolerance, for example:
if(Math.Abs((0.1 + 0.2) - 0.3) < 0.0001)
{
Console.WriteLine("Equal");
}
else
{
Console.WriteLine("Not Equal");
}
Now it will print Equal.
A fairly readable solution to this is to define an extension method for double like so:
public static class FloatAndDoubleExt
{
public static bool IsApproximately(this double self, double other, double within)
{
return Math.Abs(self - other) <= within;
}
public static bool IsApproximately(this float self, float other, float within)
{
return Math.Abs(self - other) <= within;
}
}
Then use it like so:
float myNumber = 3.146f;
if (myNumber.IsApproximately(3.146f, within:0.001f))
{
////
}
else
{
////
}
Also see the documentation for Double.Equals() for more information.
I am using recursion to add two numbers together, By adding 1 to the first input one at a time until I have reached the value of the second.
Why does this work...
private static int AddMethod(int input1, int input2)
{
if (input2 == 0)
{
Console.WriteLine(input1);
return (input1);
}
else
{
input1++;
input2--;
return AddMethod(input1, input2);
}
}
But not this..
private static int AddMethod(int input1, int input2)
{
if (input2 == 0)
{
Console.WriteLine(input1);
return (input1);
}
else
{
return AddMethod(input1++, input2--);
}
}
I am using Visual Studio 2010 and .Net 4.0
Because return AddMethod(input1++, input2--); first passes your inputs, and THEN increments and decrements.
Try
return AddMethod(++input1, --input2);
Post fix increment works by first "assigning" the value, then incrementing the value.
Compare:
int a = 1;
int b = 1;
int x = a++;
int y = ++b;
So in your case, the value you pass to AddMethod is the unchanged value, it modifies the value of input1 and input2 after they are passed.
Because the ++ and -- operators are executed after passing the values as parameters to the function.
Your code:
return AddMethod(input1++, input2--);
Is equal to:
int result AddMethod(input1, input2);
input1++;
input2--;
return result;
Instead of all this, you could use:
return AddMethod(++input1, --input2);
I have a C# code which is working good when the "optimize code" option is off, but fails otherwise. Is there any function or class attribute which can prevent the optimisation of a function or class, but let the compiler optimize the others ?
(I tried unsafe or MethodImpl, but without success)
Thanks
Edit :
I have done some more test...
The code is like this :
double arg = (Math.PI / 2d - Math.Atan2(a, d));
With a = 1 and d = 0, arg should be 0.
Thid code is a function which is called by Excel via ExcelDNA.
Calling an identical code from an optimized console app : OK
Calling this code from Excel without optimization : OK
Calling this code from Excel with optimization : Not OK, arg == 0 is false (instead arg is a very small value near 0, but not 0)
Same result with [MethodImpl(MethodImplOptions.NoOptimization)] before the called function.
This is very likely to do with the floating point mode which Excel likely has set - meaning that your program is calculating floating points slightly different because of the program (Excel) hosting your assembly (DLL). This might impact how your results are calculated, or how/what values are automatically coerced to zero.
To be absolutely sure you are not going to run into issues with different floating point modes and/or errors you should check for equality rather by checking if the values are very close together. This is not really a hack.
public class AlmostDoubleComparer : IComparer<double>
{
public static readonly AlmostDoubleComparer Default = new AlmostDoubleComparer();
public const double Epsilon = double.Epsilon * 64d; // 0.{322 zeroes}316
public static bool IsZero(double x)
{
return Compare(x, 0) == 0;
}
public static int Compare(double x, double y)
{
// Very important that cmp(x, y) == cmp(y, x)
if (Double.IsNaN(x) || Double.IsNaN(y))
return 1;
if (Double.IsInfinity(x) || Double.IsInfinity(y))
return 1;
var absX = Math.Abs(x);
var absY = Math.Abs(y);
var diff = absX > absY ? absX - absY : absY - absX;
if (diff < Epsilon)
return 0;
if (x < y)
return -1;
else
return 1;
}
int IComparer<double>.Compare(double x, double y)
{
return Compare(x, y);
}
}
// E.g.
double arg = (Math.PI / 2d - Math.Atan2(a, d));
if (AlmostDoubleComparer.IsZero(arg))
// Regard it as zero.
I also ported the re-interpret integer comparison, in case you find that more suitable (it deals with larger values more consistently).
public class AlmostDoubleComparer : IComparer<double>
{
public static readonly AlmostDoubleComparer Default = new AlmostDoubleComparer();
public const double MaxUnitsInTheLastPlace = 3;
public static bool IsZero(double x)
{
return Compare(x, 0) == 0;
}
public static int Compare(double x, double y)
{
// Very important that cmp(x, y) == cmp(y, x)
if (Double.IsNaN(x) || Double.IsNaN(y))
return 1;
if (Double.IsInfinity(x) || Double.IsInfinity(y))
return 1;
var ix = DoubleInt64.Reinterpret(x);
var iy = DoubleInt64.Reinterpret(y);
var diff = Math.Abs(ix - iy);
if (diff < MaxUnitsInTheLastPlace)
return 0;
if (ix < iy)
return -1;
else
return 1;
}
int IComparer<double>.Compare(double x, double y)
{
return Compare(x, y);
}
}
[StructLayout(LayoutKind.Explicit)]
public struct DoubleInt64
{
[FieldOffset(0)]
private double _double;
[FieldOffset(0)]
private long _int64;
private DoubleInt64(long value)
{
_double = 0d;
_int64 = value;
}
private DoubleInt64(double value)
{
_int64 = 0;
_double = value;
}
public static double Reinterpret(long value)
{
return new DoubleInt64(value)._double;
}
public static long Reinterpret(double value)
{
return new DoubleInt64(value)._int64;
}
}
Alternatively you could try and NGen the assembly and see if you can work around the either the mode Excel has, or how it is hosting the CLR.
That is what you get when working with floating point datatypes. You don't get exactly 0, but a very close value, since a double has limited precision and not every value can be represented and sometimes those tiny precision errors add up. You either need to expect that (check that the value is close enough to 0).