Property with getter always returns 0 - c#

This is blowing my mind. I have this class with the following properties:
public IEnumerable<QuestionModel> Questions { get; set; }
public int TotalQuestions
{
get
{
return Questions.Count();
}
}
public int TotalCorrect
{
get
{
return Questions.Count( x => x.Correct );
}
}
public int Score
{
get
{
return ( TotalCorrect / TotalQuestions ) * 100;
}
}
Here's how I create the model in the controller:
var model = new QuizModel
{
Questions = new List<QuestionModel>
{
new QuestionModel
{
Correct = true
},
new QuestionModel
{
Correct = false
}
}
};
TotalQuestions is equal to 2. TotalCorrect is equal to 1. But Score is always 0.
I thought maybe Score was set before the other properties were set, so I tried this:
public int Score()
{
return ( TotalCorrect / TotalQuestions ) * 100;
}
I figured this would work because by the time I called Score() in the view the other properties would be set for sure. But it just returns 0.
I also tried changing the IEnumerable to an IList. No luck there.

This is blowing my mind.
Dude. Chill. It's all good.
TotalQuestions is equal to 2. TotalCorrect is equal to 1. But Score is always 0.
Well, do the math yourself. What integer is closest to 1 / 2, rounding towards zero? Obviously zero. What is zero multiplied by 100? Obviously zero. So the answer is zero.
The problem is that you're using all-integer arithmetic. Integer division rounds off to the nearest integer which is always zero in your scenario -- unless the number of correct answers exactly equals the total number of questions, in which case it is one.
To fix the problem here are two techniques,
First, you could multiply by 100 first and then do the division.
return ( 100 * TotalCorrect ) / TotalQuestions;
Now we multiply 100 by 1, get 100, divide that by 2, get 50, done.
Or you could cast one of the integers to a decimal, do the computation in decimals, and then cast it back to integer at the end:
public int Score()
{
return (int)(( (decimal)TotalCorrect / TotalQuestions ) * 100);
}
Now we convert 1 to 1.0m, divide by 2 to get 0.5m, and multiply by 100 to get 50.0m. Then convert that to int to get 50.
Note: use decimal and not double. You are less likely to run into strange rounding errors if you do. Remember, decimal accurately represents fractions where the denominator contains any combination of powers of two and five; double only accurately represents fractions where the denominator is a power of two.
Should you ever wish to allow a non-integer score, the latter algorithm is probably better.

Your dividing an integer by an integer, so the result is an integer. Since the result is 0.5, as an integer that is 0.
Just cast either operand to a double (or decimal) first:
( TotalCorrect / (double)TotalQuestions ) * 100;

You are dividing integers, and result is getting truncated to zero. Convert the first to float or double.
public int Score()
{
return (int)(((float)TotalCorrect / TotalQuestions ) * 100);
}

Related

converting int to decimal choosing where to put decimal place

I have an interesting problem, I need to convert an int to a decimal.
So for example given:
int number = 2423;
decimal convertedNumber = Int2Dec(number,2);
// decimal should equal 24.23
decimal convertedNumber2 = Int2Dec(number,3);
// decimal should equal 2.423
I have played around, and this function works, I just hate that I have to create a string and convert it to a decimal, it doesn't seem very efficient:
decimal IntToDecConverter(int number, int precision)
{
decimal percisionNumber = Convert.ToDecimal("1".PadRight(precision+1,'0'));
return Convert.ToDecimal(number / percisionNumber);
}
Since you are trying to make the number smaller couldn't you just divide by 10 (1 decimal place), 100 (2 decimal places), 1000 (3 decimal places), etc.
Notice the pattern yet? As we increase the digits to the right of the decimal place we also increase the initial value being divided (10 for 1 digit after the decimal place, 100 for 2 digits after the decimal place, etc.) by ten times that.
So the pattern signifies we are dealing with a power of 10 (Math.Pow(10, x)).
Given an input (number of decimal places) make the conversion based on that.
Example:
int x = 1956;
int powBy=3;
decimal d = x/(decimal)Math.Pow(10.00, powBy);
//from 1956 to 1.956 based on powBy
With that being said, wrap it into a function:
decimal IntToDec(int x, int powBy)
{
return x/(decimal)Math.Pow(10.00, powBy);
}
Call it like so:
decimal d = IntToDec(1956, 3);
Going the opposite direction
You could also do the opposite if someone stated they wanted to take a decimal like 19.56 and convert it to an int. You'd still use the Pow mechanism but instead of dividing you would multiply.
double d=19.56;
int powBy=2;
double n = d*Math.Pow(10, powBy);
You can try create decimal explictly with the constructor which has been specially designed for this:
public static decimal IntToDecConverter(int number, int precision) {
return new decimal(Math.Abs(number), 0, 0, number < 0, (byte)precision);
}
E.g.
Console.WriteLine(IntToDecConverter(2423, 2));
Console.WriteLine(IntToDecConverter(1956, 3));
Outcome:
24.23
1.956
Moving the decimal point like that is just a function of multiplying/dividing by a power of 10.
So this function would work:
decimal IntToDecConverter(int number, int precision)
{
// -1 flips the number so its a fraction; same as dividing below
decimal factor = (decimal)Math.Pow(10, -1*precision)
return number * factor;
}
number/percisionNumber will give you an integer which you then convert to decimal.
Try...
return Convert.ToDecimal(number) / percisionNumber;
Convert your method like as below
public static decimal IntToDecConverter(int number, int precision)
{
return = number / ((decimal)(Math.Pow(10, precision)));
}
Check the live fiddle here.

Round to 25, 50, 75, 100

I'm not a Math person so I'm having a hard time to come up with a calculation to round the decimals to 25, 50, 75 and 100. And this will not be the typical round off because the decimals will not be decreased but only increased.
Example:
if 11.12, round to 11.25
if 11.34, round to 11.50
if 11.52, round to 11.75
if 11.76, round to 12.00
Here's my starting method:
public float RoundNearestCents(String price)
{
float srp;
return srp;
}
public float RoundNearestCents(double d)
{
return (double)(Math.Ceiling(d * 4)) / 4;
}
I suggest using types without floating point.
decimal RoundNearestCents(decimal price) {
// no problems with floating point as all calculations are exact
return Math.Floor((price * 100 + 24) / 25) * 25 / 100;
}
-- Why is your price string?
-- Because it's coming from a textbox.
I assume your textbox should support limiting your input to decimal numbers with at most 2 decimal places. So its value will be decimal already. However I don't know what is your application type. If you still want to accept string then consider using decimal.TryParse method to convert it to decimal.
My code may not be the best out there, but it will work.
In your function create a float and an int like so.
public float RoundNearestCents(String price)
{
float srp = float.Parse(price);
int srp1 = Int32.Parse(price);
if((srp-srp1)>=0.5)
srp1++;
else
return srp1;
return srp1;
}
The int would truncate out the decimal part, which is like flooring the price.
I would use something like this:
float RoundNearestCents(float price)
{
price*=(100/25.0); // now fractions are going away
if (price-floor(price)>=0.5) price++; // round up if fraction above 0.5
return floor(price)*(25.0/100.0); // cut of the fraction and restore original range
}
This is one way:
public decimal RoundNearestCents(decimal price)
{
decimal srp = price * 100;
decimal m = srp % 25;
srp = srp - m + (m > 0 ? 25 : 0);
return srp / 100;
}

Keep rounding upto specified digit if non zero

I want to round Up decimal values upto two points. But for any number which is less than 0.01, I want to return 0.01.
RoundUp(0.146,2) should return 0.15
RoundUp(0.0003,2) should return 0.01
In C#, I am currently using Math.Round, with MidpointRounding.AwayFromZero parameter, but for
Math.Round(0.0003, 2, MidpointRounding.AwayFromZero);
it returns 0.
Is there any in built method in Math namespace, which I can use to get desired behavior?
Currently I am using this method
private double GetRoundUpValue(double price, int roundUpto)
{
Debug.Assert(roundUpto == 2 || roundUpto == 3);
var val = Math.Round(price, roundUpto, MidpointRounding.AwayFromZero);
Double minValue = roundUpto == 2 ? 0.01 : 0.001;
return val < minValue ? minValue : val;
}
But for any number which is less than 0.01, I want to return 0.01.
Then why not keep it simple and just use something like this:
Math.Max(Math.Round(0.0003, 2, MidpointRounding.AwayFromZero), 0.01);
Or if you need something more general, to round to n decimal places, use something like this:
private double GetRoundUpValue(double price, int places)
{
var minValue = Math.Pow(0.1, places);
return Math.Max(Math.Round(price, places, MidpointRounding.AwayFromZero), minValue);
}
Also note, that 'rounding away from zero' is not the same as 'rounding up' (for that, you can look at Math.Ceiling). So I'd recommend either changing the name of this method or it's body to be more clear about what's actually going on inside of it.
For example:
private double GetRoundUpValue(double price, int places)
{
var scale = Math.Pow(10, places);
return Math.Ceiling(price * scale) / scale;
}

custom method for returning decimal places shows odd behavior

I am writing a simple method that will calculate the number of decimal places in a decimal value. The method looks like this:
public int GetDecimalPlaces(decimal decimalNumber) {
try {
int decimalPlaces = 1;
double powers = 10.0;
if (decimalNumber > 0.0m) {
while (((double)decimalNumber * powers) % 1 != 0.0) {
powers *= 10.0;
++decimalPlaces;
}
}
return decimalPlaces;
I have run it against some test values to make sure that everything is working fine but am getting some really weird behavior back on the last one:
int test = GetDecimalPlaces(0.1m);
int test2 = GetDecimalPlaces(0.01m);
int test3 = GetDecimalPlaces(0.001m);
int test4 = GetDecimalPlaces(0.0000000001m);
int test5 = GetDecimalPlaces(0.00000000010000000001m);
int test6 = GetDecimalPlaces(0.0000000001000000000100000000010000000001000000000100000000010000000001000000000100000000010000000001m);
Tests 1-5 work fine but test6 returns 23. I know that the value being passed in exceeds the maximum decimal precision but why 23? The other thing I found odd is when I put a breakpoint inside the GetDecimalPlaces method following my call from test6 the value of decimalNumber inside the method comes through as the same value that would have come from test5 (20 decimal places) yet even though the value passed in has 20 decimal places 23 is returned.
Maybe its just because I'm passing in a number that has way too many decimal places and things go wonky but I want to make sure that I'm not missing something fundamentally wrong here that might throw off calculations for the other values later down the road.
The number you're actually testing is this:
0.0000000001000000000100000000
That's the closest exact decimal value to 0.0000000001000000000100000000010000000001000000000100000000010000000001000000000100000000010000000001.
So the correct answer is actually 20. However, your code is giving you 23 because you're using binary floating point arithmetic, for no obvious reason. That's going to be introducing errors into your calculations, completely unnecessarily. If you change to use decimal consistently, it's fine:
public static int GetDecimalPlaces(decimal decimalNumber) {
int decimalPlaces = 1;
decimal powers = 10.0m;
if (decimalNumber > 0.0m) {
while ((decimalNumber * powers) % 1 != 0.0m) {
powers *= 10.0m;
++decimalPlaces;
}
}
return decimalPlaces;
}
(Suggestion) You could calculate that this way:
public static int GetDecimalPlaces(decimal decimalNumber)
{
var s = decimalNumber.ToString();
return s.Substring(s.IndexOf(CultureInfo.CurrentCulture.NumberFormat.NumberDecimalSeparator) + 1).Length;
}
There is another way to do this and probably it works faster because it uses remainder operation only if the decimal number has a "trailing zeros" problem.
The basic idea:
In .NET any decimal is stored in memory in the form
m * Math.Power(10, -p)
where m is mantissa (96 bit size) and p is order (value from 0 to 28).
decimal.GetBits method retrieves this representation from decimal struct and returns it as array of int (of length 4).
Using this data we can construct another decimal. If we will use only mantissa, without "Math.Power(10, -p)" part, the result will be an integral decimal. And if this integral decimal number is divisible by 10, then our source number has one or more trailing zeros.
So here is my code
static int GetDecimalPlaces(decimal value)
{
// getting raw decimal structure
var raw = decimal.GetBits(value);
// getting current decimal point position
int decimalPoint = (raw[3] >> 16) & 0xFF;
// using raw data to create integral decimal with the same mantissa
// (note: it always will be absolute value because I do not analyze
// the sign information of source number)
decimal integral = new decimal(raw[0], raw[1], raw[2], false, 0);
// disposing from trailing zeros
while (integral > 0 && integral % 10 == 0)
{
decimalPoint--;
integral /= 10;
}
// returning the answer
return decimalPoint;
}

How to ignore Decimal

I have tried to do this - Making any float value to int value. What I tried to achieve is make it 2.00-2.99 goes to 2.
Note: Im not trying to do Approximation (lower than 2.49 goes to 2, and those 2.50+ goes to 3).
I have done this so far
public int RemoveDecimal(float value)
{
string TempText = (string)value;
TempText.Remove(IndexOf('.'));
return int.parse(TempText);
}
But this will get an error when the float value ends with .00
How can I achieve this?
Thanks for any help
Math.Floor is the function you need.
It:
Returns the largest integer less than or equal to the specified number.
Example:
var val = Math.Floor(value);
Or, you could simply cast to an integer - this will simply ignore the decimal portion, so long as the range of the decimal is within the range of an int (otherwise you will get an exception):
int noDecimals = (int)value;
you can't always convert a float to an int because most of the values in float are out of range for int. you should return a string.
the following will do just that.
public string RemoveDecimal(float value)
{
string TempText = value.ToString("#");
return TempText;
}
Simply casting a floating point number to int does what you want.
i = (int)myFloat;
It truncates the fractional digits, i.e. it always goes in the direction of 0.
(int)2 == 2
(int)1.9 == 1
(int)-1.5 == -1
This will obviously not work correctly if the result is outside the valid range of int. If you want to achieve the same thing, but with a floating point number as result, Math.Truncate is what you need.

Categories

Resources