BMI & BMR calculator - c#

I'm trying to create a method that takes a user's height, weight, and age, and returns their BMI and BMR.
I think I've done this fine.
However, the last thing I need to do is add some validation to make sure the user has put in some sensible numbers. The constraints being applied to the input are:
50 [cm] ≤ height ≤ 220 [cm]
10 [kg] ≤ weight ≤ 250 [kg]
18 [years] ≤ age ≤ 70 [years]
To do this, I've tried using if statements
if (getHight >= 220 && getHight <= 50)
{
Console.WriteLine("Unfortunately, your input is incorrect, please try again");
}
else if (getAge >= 70 && getAge <= 18)
{
Console.WriteLine("Unfortunately, your input is incorrect, please try again");
}
else if (getWeight >= 250 && getWeight <= 10)
{
Console.WriteLine("Unfortunately, your input is incorrect, please try again");
}
However, regardless of what I ender, nothing shows up in the console by way of validation errors. It just outputs my BMI and BMR.
What am I missing here?

Your mistake is that you are using AND instead of OR.
You cannot both be taller than 220cm and shorter than 50cm.
Use OR operators instead of AND:
if (getHight > 220 || getHight < 50)
{
Console.WriteLine("Unfortunately, your input is incorrect, please try again");
}
else if (getAge > 70 || getAge < 18)
{
Console.WriteLine("Unfortunately, your input is incorrect, please try again");
}
else if (getWeight > 250 || getWeight < 10)
{
Console.WriteLine("Unfortunately, your input is incorrect, please try again");
}
Also as #PaulF mentioned, you should not be using <= and >= since the valid range of values is inclusive. Since your logic is the inverse (invalid values), you should drop the = and just use < and >.

As already mentioned, you should be using || instead of && when doing the comparisons and you should be using < and > since the boundary values are acceptable. You might spend some time reading up on the Boolean logical operators - AND, OR, NOT, XOR so they all make sense, because they're very common and used in just about every program you'll write.
I just wanted to add another possible solution in case you're doing a lot of these types of comparisons, which is to write an extension method for them. This way you only have to write it once, which reduces the chance of error.
Below I have an extension method that tests if a number is between a minimum and maximum value (along with an option to specify if those boundary values as valid). Note that I assumed you're testing with an int type, but you can change the type easily by changing the this int value to this double value or this float value, or whatever numeric type you're using:
public static class Extensions
{
public static bool IsBetween(this int value, int min, int max,
bool inclusive = true)
{
return inclusive ?
min <= value && value <= max:
min < value && value < max;
}
}
Now if you include that class in your project, we can use this method to test if the value is not between our accepted values by using the ! not operator. Also note that I changed the else if to separate if statements. This way, if there's more than one error, they all get reported at the same time and the user can correct them all at once. I also changed the error message so the user actually knows what's wrong and how to fix it:
// In your program class, not in the Extensions class above
if (!getHeight.IsBetween(50, 220))
{
Console.WriteLine("ERROR: Height must be an integer between 50 and 220");
}
if (!getAge.IsBetween(18, 70))
{
Console.WriteLine("ERROR: Age must be an integer between 18 and 70");
}
if (!getWeight.IsBetween(10, 250))
{
Console.WriteLine("ERROR: Weight must be an integer between 10 and 250");
}

Related

Don't know why my loop does not loop

I'm new at programming and have been working on a program that converts a saunas temperature from Fahrenheit to Celsius and then tells the user if he/she should turn the heat up or down depending on the original input number. I've done the majority of my code but now I can't see why it does not loop when I write a number below 73 degrees or over 77 degrees. Can anyone see the problem that my eyes seem to not find?
using System;
namespace BastunKP
{
class Program
{
public static int FahrToCels(int fahr)
{
int tempCels = (fahr - 32) * 5 / 9;
return tempCels;
}
public static void Main(string[] args)
{
Console.WriteLine("Skriv in Fahrenheit: ");
int fahr = int.Parse(Console.ReadLine());
int tempCels = FahrToCels(fahr);
do
{
if (tempCels < 73)
{
Console.WriteLine("Temperaturen är för kallt, skruva upp lite!");
}
else if (tempCels > 77)
{
Console.WriteLine("Temperaturen är för varmt, skruva ner lite!");
}
else
{
Console.WriteLine("Temperaturen är nu lagom, hoppa in!");
return;
}
fahr = int.Parse(Console.ReadLine());
tempCels = FahrToCels(fahr);
}
while (tempCels < 73 && tempCels > 77);
}
}
}
I also have a question regarding my assignment where the teacher has said that for a higher grade I should look into where the formula for converting fahrenheit to celsius and make it a double but I dont know how to do this change at all.
Thanks in advance
tempCels < 73 && tempCels > 77 is never true!
Most probably you wanted || so to run when temp is less than 73 or greater than 77, but who knows.
Welcome to StackOverflow! Now, let's get down to your question:
First off, consider your do-while loop.
do {
if (tempCels < 73) {
// Temperature too high
Console.WriteLine("Temperaturen är för kallt, skruva upp lite!");
} else if (tempCels > 77) {
// Temperature too low
Console.WriteLine("Temperaturen är för varmt, skruva ner lite!");
} else {
// Temperature just right, hop in!
Console.WriteLine("Temperaturen är nu lagom, hoppa in!");
return;
}
fahr = int.Parse(Console.ReadLine());
tempCels = FahrToCels(fahr);
}
while (tempCels < 73 || tempCels > 77);
As you can see, I removed the unnecessary else condition. What happens right now, is that all possible conditions are checked (temp < 73, temp > 77, and 73 < temp < 77).
One mistake you had, also pointed out in other answers, is that you had && (AND) instead of || (OR). And of course, a value cannot be both under 73 and above 77 :)
Now, I'd like to also point out some styling / general things I think you should 'fix':
1) Your temp conversion method contains an unnecessary variable creation and assignment. You can make it work just as well without it, like this:
public static int fahrToCels(int fahr) {
// It returns just the same, without needing to create a new,
// temporary temperature variable!
return (fahr - 32) * 5 / 9;
}
2) This might be debatable, but general naming conventions say that function names are written with camelCase.
3) While this is not a problem in your scenario specifically, it might become one when you scale up an application (or work on a bigger one).
It's best to use slightly more descriptive namings (in a bigger project, just fahr might be confusing). Again, it's not any big deal of a problem, just something for you to consider for the future :)
P.S. I did not change variable names in my examples, just to keep it more readable/relateable to the code you showed.
EDIT:
As per request, here is how to keep the values as double type.
// Notice the return type and the property types are both double.
public static double fahrToCels(double fahr) {
return (fahr - 32) * 5 / 9;
}
This way, values don't have to be only integers, and produce weird results on division - they can be of type double too!
Now, remember you will need to pass a variable of type double to the function, otherwise you will get a type error.
Hint:
double fahr = int.Parse(Console.ReadLine());
Will let the user pass a non-integer value (like, say, 17.7), and it will be stored properly.
Hint #2:
If you really want to do on the fly conversion, you can achieve this like this (example values):
int ourInteger = 4;
double ourNewDoubleNumber = (double)ourInteger / 23;
You can read more about types and type casting here: Types and Type Casting
tempCels (or any number, for that matter) can't be less than 73 and more than 77 at the same time. You should use the logical || operator, not the logical && operator:
do {
// code
} while (tempCels < 73 || tempCels > 77);
// Here ---------------^
while will loop when the condition is true, but tempCels cannot be <73 and >77 at the same time! Fix that condition and it will work.

C# Problems while calculating Letter Frequency percentage

I am very unskilled in programming and I am trying to finish this task for my class. I've looked all over the Internet but still can't find the answer.
Here I have a piece of my code which prints out letters and the number of times it was spotted in my text file:
for (int i = 0; i < (int)char.MaxValue; i++)
{
if (c[i] > 0 &&
char.IsLetter((char)i))
{
Console.WriteLine("Letter: {0} Frequency: {1}",
(char)i,
c[i]);
}
I've calculated the number of letters in my code using int count = s.Count(char.IsLetter);
Dividing the c[i], obviously, doesn't work. I've tried several other methods but I keep getting errors. I feel like the solution is very simple but I simply can't see it. I hope that you will be willing to help me out :)
You could use a dictionary to store the frequency of each letter. You also shouldn't loop with the constraint i < (int)char.MaxValue. This will put you out of bounds unless c's length is >= char.MaxValue.
var frequency = new Dictionary<char, int>();
for (var i = 0; i < c.Length; i++)
{
var current = (char)c[i];
if (current > 0 && char.IsLetter(current))
{
if (!frequency.ContainsKey(current))
frequency.Add(current);
frequency[current]++;
Console.WriteLine("Letter: {0} Frequency: {1}", current, frequency[current]);
}
}
Maybe you have an integer division when you want a floating point division? In that case, cast either the dividend or the divisor to double (the other one will be converted automatically), for example:
(double)c[i] / count
Edit: Since you write percentage, if you need to multiply by one hundred, you can also make sure that literal is a double, then if you are careful with the precedence of the operators, you can have all casts implicit. Example:
Console.WriteLine($"Letter: {(char)i} Count: {c[i]} Percentage {c[i] * 100.0 / count}");
The multiplication goes first because of left-associativity. The literal 100.0 has type double.

Enter a code branch every ten percent till 100 percent

I can think of some very convoluted methods with loops and nested loops to solve this problem but I'm trying to be more professional than that.
My scenario is that I need to enter a section of code every ten percent but it isn't quite working as expected. It is entering the code about every percent which is due to my code but I lack the knowledge to know how to change it.
int currentPercent = Math.Truncate((current * 100M) / total);
//avoid divide by zero error
if (currentPercent > 0)
{
if (IsDivisible(100, currentPercent))
{
....my code that works fine other than coming in too many times
}
}
Helper referenced above where the trouble is:
private bool IsDivisible(int x, int y)
{
return (x % y) == 0;
}
So obviously it works as it should. Mod eliminates currentPercent of 3 but 1 & 2 pass when really I don't want a true value until currentPercent = 10 and then not again till 20...etc.
Thank you and my apologies for the elementary question
Mod will only catch exact occurrences of your interval. Try keeping track of your next milestone, you'll be less likely to miss them.
const int cycles = 100;
const int interval = 10;
int nextPercent = interval;
for (int index = 0; index <= cycles; index++)
{
int currentPercent = (index * 100) / cycles;
if (currentPercent >= nextPercent)
{
nextPercent = currentPercent - (currentPercent % interval) + interval;
}
}
I might misunderstand you, but it seems like you're trying to do something extremely simple more complex than it needs to be. What about this?
for (int i = 1; i <= 100; i++)
{
if (i % 10 == 0)
{
// Here, you can do what you want - this will happen
// every ten iterations ("percent")
}
}
Or, if your entire code enters from somewhere else (so no loop in this scope), the important part is the i % 10 == 0.
if (IsDivisible(100, currentPercent))
{
....my code that works fine other than coming in too many times
}
try changing that 100 to a 10. And I think your x and y are also backwards.
You can try a few sample operations using google calculator.
(20 mod 10) = 0
Not sure if I fully understand, but I think this is what you want? You also reversed the order of modulo in your code (100 mod percent, rather than the other way around):
int currentPercent = current * 100 / total;
if (currentPercent % 10 == 0)
{
// your code here, every 10%, starting at 0%
}
Note that code this way only works properly if you are guaranteed to hit every percentage-mark. If you could, say, skip from 19% to 21% then you'll need to keep track of which percentage the previous time was to see if you went over a 10% mark.
try this:
for (int percent = 1; percent <= 100; percent++)
{
if (percent % 10 == 0)
{
//code goes here
}
}
Depending on how you increment your % value, this may or may not work % 10 == 0. For example jumping from 89 to 91 % would effectively skip the code execution. You should store last executed value, 80 in this case. Then check if interval is >= 10, so 90 would work, as well as 91.

Checking a TextBox for an empty string, an integer or a string

I am checking a text box for the following
If there is no input
If the input is between 0 and 100
If the input is a string other than a number
The code -
if (this.BugCompPct.Text == String.Empty)
else if (Convert.ToInt32(this.BugCompPct.Text) > 100 | Convert.ToInt32(this.BugCompPct.Text) < 0)
//Not sure about checking the last if
What could I put as the if conditional to check for a string other than an integer?
I want only the input to be an integer and nothing else
Thanks
What could I put as the if conditional to check for a string other
than an integer?
Use int.TryParse method to see if the parsing is succesfull.
For empty string use string.IsNullOrWhiteSpace (supported on .Net framework 4.0 and later), For .Net framework 3.5 or lower you can use string.IsNullOrEmpty with string.Trim
Your check will all the conditions could be like:
if (!string.IsNullOrWhiteSpace(BugCompPct.Text))
{
int temp;
if(int.TryParse(BugCompPct.Text,out temp)
{
if(temp >= 0 && temp <= 100)
{
//valid number (int)
}
else
{
//invalid number (int)
}
}
else
{
//Entered text is not a number (int)
}
}
else
{
//string is empty
}
First check if TextBox is empty, then if string is valid number and last check boundaries.
int number = 0;
if (string.IsNullOrEmpty(this.BugCompPct.Text)
{
//not valid
}
else if (Int32.TryParse(this.BugCompPct.Text, out number))
{
if (number > 0 && number < 100)
{
//valid
}
}
every value put into a textbox is as string. I would then advise you to tryparse rather than convert.to.
(Why? tryparse can be handled much easier and won't crash and burn if there are bad values put into it)
just use int.TryParse(txtbox1.text, out i)
You must define integer i above this
then you can use if statements using i (the integer version) to validate it.
To check if its an integer only just use:
if(!int.TryParse(txtbox1.text, out i))
{
// do work
}
then you can use > < in if statements to check how big the number is.
If you are on windows form you should use masked textbox.

C# Using Enumerable.Range()

Am I using this is the correct manner? As far as I understand it, the following check should be false:
int myVal = 37;
if (Enumerable.Range(0, 10).Contains(myVal))
// Do something
else if (Enumerable.Range(11, 33).Contains(myVal))
// Do somethiong else
But I seem to be getting some cases where //Do somethiong else is executed. Can I not use Enumerable.Range is this way?
The signature for Enumerable.Range provides a clue:
public static IEnumerable<int> Range(
int start,
int count
)
The first parameter is called start; the second is called count. So your second call is returning 33 values starting with 11, which will include 37.
If this particular example, its inefficient to create an enumerate in this fashion simply to check that a value lies within a particular range. if (x < y) is probably better.
It will result in every value being checked, and is a little confusing, why not do:
int myVal = 37;
if (myVal >= 0 && myVal <= 10)
// Do something
else if (myVal <= 33)
// Do somethiong else

Categories