Comparing a Decimal within a Number Range - c#

ok I am running into a problem. I have a decimal in a textbox that I am trying to Range between a set number. As you can see in the picture I have a value that is in the Full Scale, which updates the value on the CalCert with the decimal 2.9995 mV/V.
The issue here is the decimal value has to be plus/minus 30 of 3 mV. example. 2.9970 - 3.0030 that is the range. Anything outside the range I am needing it to trigger a warning dialog. My code that I was going to use I am not sure why its not working.
I am using if statements but the only error is in the ("3.0031") section.
double value = 0;
if (double.TryParse(TxtFullScale.Text, out value))
{
value /= 10000;
}
TxtCalFullScale.Text = string.Format("{0:#.0000}", value) + " " + "mV/V";
if (TxtFullScale.Text >= TxtFullScale.Text.ToString("3.0031"))
{
MessageBox.Show("Full Scale value is in a non conformence state.");
}
else if (TxtFullScale.Text <= TxtFullScale.Text.ToString("2.9970"))
{
MessageBox.Show("Full Scale value is in a non conformence state.");
}
I can take and make the code work with to a point with
if (TxtFullScale.Text == "3.0031")
{
MessageBox.Show("Full Scale value is in a non conformence state.");
}
else if (TxtFullScale.Text =="2.9970")
{
MessageBox.Show("Full Scale value is in a non conformence state.");
}
However if the range is put in the text as 3.0032 then it never shows the messagebox. What am I missing here?

So, first, you can't do math operations with strings on C#
var a = "3";
var b = "2";
Console.WriteLine(a+b);
Will result in 32!
Second, this line is a bit strange
TxtFullScale.Text >= TxtFullScale.Text.ToString("3.0031")
Should be like
TxtFullScale.Text >= "3.0031"
you need to parse the number as an decimal, then compare, like this:
public const double LIMIT_1 = 3.0031;
public static void Main()
{
var val = "3.0032";
var x = double.TryParse(val, out double dec);
if(dec >= LIMIT_1)
Console.WriteLine("yay");
}

Related

How to format numbers in scientific notation with powers in superscript

I need to write values like:
9.6 x 10²
9.6 x 10¹²
I need to know if there is a way to format numbers as above in a string.
You have to find the appropriate character from the code page you are using, for example UTF-8:
string superScript2 = "²";
There is no such thing as formatting in a string, it is just all data.
Try this:
public static string Eng(this double x, string format="g")
{
const string sup_signs = "⁺⁻⁼⁽⁾ⁿ";
const string sup_digits = "⁰¹²³⁴⁵⁶⁷⁸⁹";
if(double.IsNaN(x) || double.IsInfinity(x))
{
return x.ToString();
}
int num_sign = Math.Sign(x);
x = Math.Abs(x);
// group exponents in multiples of 3 (thousands)
int exp = (int)Math.Floor(Math.Log(x, 10)/3)*3;
// otherwise use:
// int exp = (int)Math.Floor(Math.Log(x, 10));
// and handle the exp==1 case separetly to avoid 10¹
x*= Math.Pow(10, -exp);
int exp_sign = Math.Sign(exp);
exp = Math.Abs(exp);
// Build the exponent string 'dig' from right to left
string dig = string.Empty;
while(exp>0)
{
int n = exp%10;
dig = sup_digits[n] + dig;
exp = exp/10;
}
// if has exponent and its negative prepend the superscript minus sign
if(dig.Length>0 && exp_sign<0)
{
dig = sup_signs[1] + dig;
}
// prepend answer with minus if number is negative
string sig = num_sign<0 ? "-" : "";
if(dig.Length>0)
{
// has exponent
return $"{sig}{x.ToString(format)}×10{dig}";
}
else
{
// no exponent
return $"{sig}{x.ToString(format)}";
}
}
As a test case run
static void Main(string[] args)
{
// Type code here.
double x = Math.PI/50e5;
for(int i = 0; i < 20; i++)
{
// Format output to 12 wide column, right aligned
Debug.WriteLine($"{ Eng(x, "g4"),12}");
x*=50;
}
}
with the output:
628.3×10⁻⁹
31.42×10⁻⁶
1.571×10⁻³
78.54×10⁻³
3.927
196.3
9.817×10³
490.9×10³
24.54×10⁶
1.227×10⁹
61.36×10⁹
3.068×10¹²
153.4×10¹²
7.67×10¹⁵
383.5×10¹⁵
19.17×10¹⁸
958.7×10¹⁸
47.94×10²¹
2.397×10²⁴
119.8×10²⁴
By no means optimized, but it does the job. The exponents are in engineering form (multiples of 3 only, in order to avoid things like 10¹). As a bonus, the number can be formatted to a specific number of significant digits by supplying a format code like g4 or g5 for 4 or 5 digits respectively.
It can handle negative or positive numbers
It can handle negative or positive exponents of 10
In can format the mantissa
It can handle NAN or Inf.
It's in extension form for re-usability
As a follow up to my comment above - does something like this do what you require :
public String FormatAs10Power(decimal val)
{
string SuperscriptDigits = "\u2070\u00b9\u00b2\u00b3\u2074\u2075\u2076\u2077\u2078\u2079";
string expstr = String.Format("{0:0.#E0}", val);
var numparts = expstr.Split('E');
char[] powerchars = numparts[1].ToArray();
for (int i = 0; i < powerchars.Length; i++)
{
powerchars[i] = (powerchars[i] == '-') ? '\u207b' : SuperscriptDigits[powerchars[i] - '0'];
}
numparts[1] = new String(powerchars);
return String.Join(" x 10",numparts);
}
See : https://dotnetfiddle.net/dX7LAF
As per my comment above - the number is first converted to an exponential format string (https://learn.microsoft.com/en-us/dotnet/standard/base-types/standard-numeric-format-strings#EFormatString), that string is then split on the exponential separator 'E'. The first array is the numeric part, the second the power of 10 to which it is raised - this is converted to superscript characters using one of the techniques of the link I gave (Convert a string/integer to superscript in C#), converted back to a string & the two parts combined using "x 10" as the new separator.
I have assumed you want the value to single digit precision as per your example with no preceding + sign. If you need anything else you could pass the format as a parameter. The code for superscript + is '\u207A'. There is a link here (at the time of writing) giving the list of superscript codes : http://unicode.org/charts/PDF/U2070.pdf

C# Accessing an array of labels from another form and altering their "Text" property

This is my first post. So..critique is always welcomed.
My question is straight forward just by looking at the title.
How can I use a loop to insert values to different labels by using their reference (get,set methods are in a different form)
What I've tried is to create an array with the references of the labels. The thing is.. it assigns the new values to the array rather than changing the reference which will change the label.
I find it a bit difficult to explain it further than that.
If you have any questions, I will try to answer them best to my knowledge
private void button1_Click(object sender, EventArgs e)
{
int numOfPeriods = Convert.ToInt32(cmbPeriods.Text)-1;
string initialString = cmbStartTime.Text; //Gets the input from combo box "cmbStartTime".
string newTime;
decimal dec = Convert.ToDecimal(TimeSpan.Parse(initialString).TotalHours); //Converts the set by user Lesson start time to a decimal value.
decimal dec2;
decimal lessonLength = 1; // Default lesson length is set to 1 hour.
TimeSpan time;
Test FormOpen = new Test();
string[] periodStartTimes = new string[9] //Loop referencing the labels on Form TEST
{
FormOpen.startTime,FormOpen.startTime2, FormOpen.startTime3, FormOpen.startTime4,
FormOpen.startTime5, FormOpen.startTime6, FormOpen.startTime7, FormOpen.startTime8,
FormOpen.startTime9
};
if (cmbLessonLength.Text != "") //If the combo box "cmbLessonLength" is not empty, use that value instead of the default lesson lenght.
{
lessonLength = Convert.ToDecimal(cmbLessonLength.Text)/60; //Converts minutes to hours.
}
dec2 = dec + lessonLength;
time = TimeSpan.FromHours(Double.Parse(dec2.ToString()));
newTime = time.ToString();
if (newTime[0] == '0')
{
FormOpen.startTime = initialString + " - " + newTime.Remove(5).Remove(0, 1);
}
else
{
FormOpen.startTime = initialString + " - " + newTime.Remove(5);
}
for (int x = 1; x <= numOfPeriods; x++) //LOOP THAT ASSIGNS VALUES TO THE ARRAY AND NOT THE REFERENCE INSIDE IT
{
decimal workingNumber = lessonLength*x;
decimal Convert0 = dec + workingNumber;
TimeSpan Convert1 = TimeSpan.FromHours(Double.Parse(Convert0.ToString()));
string Convert2 = Convert1.ToString().Remove(5);
periodStartTimes[x] = Convert2;
}
FormOpen.subjectName = cmbSubjects.Text;
FormOpen.startTime2 = periodStartTimes[1]; //IT DOES WORK LIKE THIS
FormOpen.startTime3 = periodStartTimes[2];
FormOpen.ShowDialog();
}
I have provided the whole code, so it's clearer and if there's a more efficient way of coding this I would be really thankful if someone could give me a few tips.
Your code cannot work using that array periodStartTimes This is an array of strings and when you initialize it you get the value of the property (IE the current text of the labels) not a reference to a property that you can use to change the labels.
In any case it is a bad practice to allow a different class instance change the internal values of another class. It is better to provide a public method used by the external classes to change the internal properties.
So for example your Test form class could have a public method named as SetTextLabel
public class Test : Form
{
....
public void SetLabelText(string name, string value)
{
switch(name)
{
case "startTime":
this.labelForStartTime.Text = value;
break;
case "label1":
this.firstLabelToUpdate.Text = value;
break;
...
// and so on for all other labels
}
}
}
In this way the code that changes the label is inside the Test class and you can add all the checks and validations required with full access to all the internal variables of the Test class.
Now your loop can be rewritten as
for (int x = 1; x <= numOfPeriods; x++)
{
decimal workingNumber = lessonLength*x;
decimal Convert0 = dec + workingNumber;
TimeSpan Convert1 = TimeSpan.FromHours(Double.Parse(Convert0.ToString()));
string Convert2 = Convert1.ToString().Remove(5);
FormOpen.SetLabelText("label" + x.ToString, Convert2;
}
Of course now you don't need anymore the array, and this will probably remove another error present in your actual code. The array is fixed at 9 elements but you loop for numOfPeriods starting from 1 (thus skipping the first element) and if numOfPeriods is bigger than 8 your code will crash with IndexOutOfRange exception

Getting a format exception parsing a string to a double

So there are still some logic errors in this that I am working on. I'm not worried about those, and I want to figure them out myself.
I'm working on a slot machine app for some independent study and when I try to parse the value of the label that shows the players cash into a variable I am getting a format exception. How do fix this and more importantly why am I getting this exception?
I have also tried using TryParse and Convert.ToDouble.
protected void PullBTN_Click(object sender, EventArgs e)
{
// Get players cash//////////////////////////////
double playersCash = Convert.ToDouble(playerMoneyLBL.Text);
// Other way I tried that didn't work ////////////
//double playersCash = 0;
//double.TryParse(playerMoneyLBL.Text.Trim(), out playersCash);
// Get players bet /////////////////////////////
double playerBet = 0;
if (!double.TryParse(betTB.Text, out playerBet))
return;
// Spin the slots//////////////////////////////
Image1.ImageUrl = spinReel();
Image2.ImageUrl = spinReel();
Image3.ImageUrl = spinReel();
// Find multiplier //////////////////////////////
double multiplier = findMultiplier();
// Find winnings ///////////////////////////////
double winnnings = multiplier * playerBet;
playerMoneyLBL.Text = (playersCash + winnnings).ToString();
// Add winnings to players money //////////////
playerMoneyLBL.Text = (playersCash + winnnings).ToString();
}
Your problem is here.
playerMoneyLBL.Text = "$100";
As you have $ in-front of 100, you cannot convert that to float. Make it something like this.
double playersCash = Convert.ToDouble(playerMoneyLBL.Text.substring(1));
double.Parse uses your CurrentCulture settings on the current environment by default.
double d = double.Parse("Your Text Here", CultureInfo.InvariantCulture);
Or if you want it more secure way, try:
value = "Your String";
style = NumberStyles.Number | NumberStyles.AllowCurrencySymbol| NumberStyles.AllowThousands;
culture = CultureInfo.InvariantCulture
if (Double.TryParse(value, style, culture, out number))
{
// Write your code for true condition
}
else
{
// Write your code for false condition
}

Need only 2 digits after decimal point

I want my function to return value with only 2 decimal places. I have tried following code :
private static double CalculateSlabTax(int nSlabStartTaxable,
int nSlabEndTaxable,
float fSlabRate)
{
double dblSlabResult = 0;
try
{
dblSlabResult = (nSlabStartTaxable - nSlabEndTaxable) * fSlabRate;
dblSlabResult = Math.Round(dblSlabResult , 2);
return dblSlabResult;
}
catch (Exception)
{
return -1;
}
}
Expected output is : dblSlabResult = ####.## - two digits (eg. 1002.05)
Getting output as : eg. dblSlabResult = 1002.1
To represent use formatting. In your case exactly two digits after decimal point means "F2" format string
double source = 1234.56789;
// 1234.57
var result = source.ToString("F2");
Very simple. Try this
public double UptoTwoDecimalPoints(double num)
{
var totalCost = Convert.ToDouble(String.Format("{0:0.00}", num));
return totalCost;
}
The # character is an optional digit placeholder. Use 0 to enforce digits when converting to string:
string.Format("{0:#.##}", 1002.1) == "1002.1"
string.Format("{0:0.00}", 1002.1) == "1002.10"
Don't expect a specific count of digits when rounding float or double. They are just numbers, independent of their string format.
What inputs are you using? Math.Round should be working correctly, which suggests that the line above is returning a double with only 1 significant figure.

Formatting decimals without rounding

I am fairly new to C# and was wondering if someone could help out with the below code. I am having trouble finding an IF statement to insert into "---------INSERT IF STATEMENT HERE". I am utilizing SQL Convert(Decimal (28,10)) to limit numerical values to 10 decimal spots. Basically, I would like to remove zero's within the report designer by utilizing C#. Few examples below:
Preferred formatting: 4.25 vs 4.2500000000
Preferred formatting: 0.00 vs 0.0000000000
No point having extra zeroes.
Current Notional Amount : 22,000,000.00
Hypothetical example:
22,000,000.12344567890 (up to 10 decimals when available)
I was able to remove zero's with the below code; however, I am limited to two zero's for all my numerical values. So 4.2500000000 shows as 4.25, but 4.2511 would actually show up as 4.25. Can someone please help?
public void Detail1_Format()
{ DataDynamics.ActiveReports.TextBox tb1;
String s;
Double d;
String ColName;
s = ((DataDynamics.ActiveReports.TextBox) rpt.Sections["Detail1"].Controls["txtValue1"]).Text;
ColName = ((DataDynamics.ActiveReports.TextBox) rpt.Sections["Detail1"].Controls["txtColName1"]).Text;
if((ColName == "Price") || (ColName == "Shares (Par or Notional)"))
{
if(Double.TryParse(s, out d) == true)
{
d = Convert.ToDouble(s);
tb1 = (DataDynamics.ActiveReports.TextBox) rpt.Sections["Detail1"].Controls["txtValue1"];
---------INSERT IF STATEMENT HERE
{tb1.Text = d.ToString("#,###.##########");}
---------else {
{tb1.Text = d.ToString("#,###.00");
}
((DataDynamics.ActiveReports.TextBox) rpt.Sections["Detail1"].Controls["txtValue1"]).Text = tb1.Text;}
}
else {
((DataDynamics.ActiveReports.TextBox) rpt.Sections["Detail1"].Controls["txtValue1"]).Text = ((DataDynamics.ActiveReports.TextBox) rpt.Sections["Detail1"].Controls["txtValue1"]).Text;
}
}
To make sure I understand, you want to remove trailing 0s beyond 2 decimal places and possibly have 10 decimals.
If so, you are very close and you can tweak some things with the simple string formatting to do this.
d = Convert.ToDouble(s);
tb1 = (DataDynamics.ActiveReports.TextBox) rpt.Sections["Detail1"].Controls["txtValue1"];
tb1.Text = d.ToString("#,##0.00########");
Here the format #,##0.00######## will require 2 decimal places (signified by a 0) and the remaining 8 are optional (signified by a #).
Examples
Convert.ToDecimal("0.0000000000").ToString("#,##0.00########"); // 0.00
Convert.ToDecimal("4.2500000000").ToString("#,##0.00########"); // 4.25
Convert.ToDecimal("22,000,000.1234567890").ToString("#,##0.00########"); // 22,000,000.123456789
Convert.ToDecimal("22,000,000.1234567891").ToString("#,##0.00########"); // 22,000,000.1234567891
Thanks for your help. I was able to modify your suggestion, Kirk and add additional logic. I added another variable (d2) and inserted one more if statement to allow for more than 2 decimal places for values such as 103.123456. Please see below:
public void Detail1_Format()
{ DataDynamics.ActiveReports.TextBox tb1;
String s;
Double d;
Decimal d2;
String ColName;
s = ((DataDynamics.ActiveReports.TextBox) rpt.Sections["Detail1"].Controls["txtValue1"]).Text;
ColName = ((DataDynamics.ActiveReports.TextBox) rpt.Sections["Detail1"].Controls["txtColName1"]).Text;
if((ColName == "Price" || ColName == "Original Face Value" || ColName == "Shares"))
{
if(Double.TryParse(s, out d) == true)
{
d = Convert.ToDouble(s);
tb1 = (DataDynamics.ActiveReports.TextBox) rpt.Sections["Detail1"].Controls["txtValue1"];
d2 = Convert.ToDecimal(s);
if((BitConverter.GetBytes(decimal.GetBits(d2)[3])[2]) > 2)
{tb1.Text = d.ToString("#,##0.00########");}
else
{tb1.Text = d.ToString("#,###.00");
}
((DataDynamics.ActiveReports.TextBox) rpt.Sections["Detail1"].Controls["txtValue1"]).Text = tb1.Text;}
}
else {
((DataDynamics.ActiveReports.TextBox) rpt.Sections["Detail1"].Controls["txtValue1"]).Text = ((DataDynamics.ActiveReports.TextBox) rpt.Sections["Detail1"].Controls["txtValue1"]).Text;
}
}

Categories