Formatting decimals without rounding - c#

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;
}
}

Related

Comparing a Decimal within a Number Range

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");
}

Maximum product of 13 adjacent numbers

List<int> arr = new List<int>();
long max = 0;
long mul = 1;
string abc = #"73167176531330624919225119674426574742355349194934
85861560789112949495459501737958331952853208805511
96983520312774506326239578318016984801869478851843
12540698747158523863050715693290963295227443043557
66896648950445244523161731856403098711121722383113
62229893423380308135336276614282806444486645238749
30358907296290491560440772390713810515859307960866
70172427121883998797908792274921901699720888093776
65727333001053367881220235421809751254540594752243
52584907711670556013604839586446706324415722155397
53697817977846174064955149290862569321978468622482
83972241375657056057490261407972968652414535100474
82166370484403199890008895243450658541227588666881
16427171479924442928230863465674813919123162824586
17866458359124566529476545682848912883142607690042
24219022671055626321111109370544217506941658960408
07198403850962455444362981230987879927244284909188
84580156166097919133875499200524063689912560717606
05886116467109405077541002256983155200055935729725
71636269561882670428252483600823257530420752963450";
foreach (char a in abc)
{
if(arr.Count == 13)
{
arr.RemoveAt(0);
}
int value = (int)Char.GetNumericValue(a);
arr.Add(value);
if(arr.Count == 13)
{
foreach(int b in arr)
{
mul = mul * b;
if (mul > max)
{
max = mul;
}
}
mul = 1;
}
}
Console.WriteLine(max);
I am getting 5377010688 which is a wrong answer and when I am trying same logic with given example in project Euler it is working fine, please help me.
Don't say the answer just correct me where I am doing wrong or where the code is not running as it should.
The string constant, as it is written down like above, contains blanks and \r\n's, e.g. between the last '4' of the first line and the first '8' on the second line. Char.GetNumericValue() returns -1 for a blank.
Propably the character sequence with the highest product spans across adjacent lines in your string, therefore there are blanks in between, which count as -1, which disables your code in finding them.
Write your constant like this:
string abc = #"73167176531330624919225119674426574742355349194934" +
"85861560789112949495459501737958331952853208805511" +
"96983520312774506326239578318016984801869478851843" + etc.
The result is then 23514624000, I hope that's correct.
Don't say the answer just correct me where I am doing wrong or where
the code is not running as it should
You have included all characters into calculation but you should not do that. The input string also contains for example carriage return '\n' at the end of each line.
Your actual string look like this:
string abc = #"73167176531330624919225119674426574742355349194934\r\n
85861560789112949495459501737958331952853208805511\r\n
...
How to solve this? You should ignore these characters, one possible solution is to check each char if it is a digit:
if(!char.IsDigit(a))
{
continue;
}

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

Count Zeroes before the Decimal Point

I am trying to count how many zeroes are a before a decimal.
private void textBox1_TextChanged(object sender, EventArgs e)
{
decimal x = 0;
if (Decimal.TryParse(textBox1.Text, out x))
{
var y = 1000000;
var answer = x * y;
displayLabel2.Text = (x.ToString().Replace(".", "").TrimStart(new Char[] { '0' }) + "00").Substring(0, 2);
}
else
{
displayLabel2.Text = "error";
}
}
When I plug in (lets say) 7.2 I get an output that displays 72, which is what I want. Now I need another display. That initial 7.2 is being multiplied by 1000000. So the quotent of that would be 7,200,000.00. Now I need to some how count the 5 zeroes before the decimal point and display 5 for that. Then if I were to do .72. My Quotent would be 720,000.00. And I would need to display 4, for the 4 zeroes. And so on. Then I need to output that number to displayLabel5.Text
Here's a one line Linq you could try to count zeroes before the decimal. You can Split() first by the decimal then perform a Where().Count() to get the number of zeros.
using System;
using System.Linq;
public class Program
{
public static void Main()
{
string myString = (720000.00).ToString();
Console.WriteLine(myString.Split('.')[0].Where(d => d == '0').Count());
}
}
Results:
4
Demo
Quick and dirty code so be careful, but AFAIK this is the fastest way to do it.
// Input assuming you've sanitised it
string myInputString = "720000.00";
// Remove the decimals
myInputString = myInputString.Substring(0, myInputString.IndexOf("."));
// The count
int count = 0;
// Loop through and count occurrences
foreach (char c in myInputString)
{
if (c == "0")
{
count++;
}
}
Count is now 4.
Guarantee you this is faster than Regex ;-)
Edit: Sorry for the multiple edits, it's been a long day. Need coffee.
use a regular expression to find all the zeros before the period, then get the string length of that match.
Regex regex = new Regex(#"(0+)\.?");
string value1 = "7,200,000.00";
value1 = value1.Replace(",",""); //get rid of the commas
Match match = regex.Match(value1);
if (match.Success)
{
Console.WriteLine(match.Value.Length);
}
As always test the code because I wrote it just now here in this little text box and not in actual visual studio where I could compile and test it myself. But this should at least illustrate the methodology.
Edit:
slight tweak to the regex to account for the possibility that the number will not display a decimal point at all.

String Fraction to Double

I need a function to parse a user inputs of numbers to doubles. I cannot do anything client side or change how the input comes in.
Input | Desired Output
"9" | 9
"9 3/4" | 9.75
" 9 1/ 2 " | 9.5
"9 .25" | 9.25
"9,000 1/3" | 9000.33
"1/4" | .25
I saw this post, but it uses Python, I was just wondering if anybody knew any fancy C# ways of handling this before I spend time to write my own.
I would use regular expressions for this one:
Regex re = new Regex(#"^\s*(\d+)(\s*\.(\d*)|\s+(\d+)\s*/\s*(\d+))?\s*$");
string str = " 9 1/ 2 ";
Match m = re.Match(str);
double val = m.Groups[1].Success ? double.Parse(m.Groups[1].Value) : 0.0;
if(m.Groups[3].Success) {
val += double.Parse("0." + m.Groups[3].Value);
} else {
val += double.Parse(m.Groups[4].Value) / double.Parse(m.Groups[5].Value);
}
Untested, as of yet, but I think it should work.
Here's a demo, and here's another demo.
There is nothing built in the BCL that will do this, but there are plenty of existing mathematical expression parsers that will (though this may be over the top for this specific situation).
Writing one yourself, for the limited use cases you have posted shouldn't be difficult.
I see two sections. Everything before the first space is the integral section. Everything after the first space is the fractional section. After you separate the two sections, you can just strip spaces from the fractional section, split that section on the / character, and divide the first part by the 2nd part (if there is a 2nd part). Then add the result to the integral section to find your answer.
This algorithm should give a correct result for each of your samples. It might also give an incorrect result for samples like these: "9 .25/4" or "9 3/0", so those are things to watch for. Other things include leading whitespace, whether you want to allow other whitespace, currency symbols, whether "9.25" (no spaces) is a valid input, and what to do with irrational fractions like "1/3", "1/10" (irrational in binary), etc.
I'm not normally a huge believer in test driven design (that you should write the tests first and go for 100% coverage) for static-typed languages, but I do think unit tests have value in certain specific situations, and this is one of those situations. I would put together a few tests for both some common and edge cases, such that you can be sure whatever you end up with handles the inputs correctly to pass the tests.
Here's what I ended up using:
private double ParseDoubleFromString(string num)
{
//removes multiple spces between characters, cammas, and leading/trailing whitespace
num = Regex.Replace(num.Replace(",", ""), #"\s+", " ").Trim();
double d = 0;
int whole = 0;
double numerator;
double denominator;
//is there a fraction?
if (num.Contains("/"))
{
//is there a space?
if (num.Contains(" "))
{
//seperate the integer and fraction
int firstspace = num.IndexOf(" ");
string fraction = num.Substring(firstspace, num.Length - firstspace);
//set the integer
whole = int.Parse(num.Substring(0, firstspace));
//set the numerator and denominator
numerator = double.Parse(fraction.Split("/".ToCharArray())[0]);
denominator = double.Parse(fraction.Split("/".ToCharArray())[1]);
}
else
{
//set the numerator and denominator
numerator = double.Parse(num.Split("/".ToCharArray())[0]);
denominator = double.Parse(num.Split("/".ToCharArray())[1]);
}
//is it a valid fraction?
if (denominator != 0)
{
d = whole + (numerator / denominator);
}
}
else
{
//parse the whole thing
d = double.Parse(num.Replace(" ", ""));
}
return d;
}
It doesn't look very difficult to write some code that would do this. First try removing all spaces and see if it's a legal number. If it's not, find the legal numbers (such as 9, 3, 4 in "9 3/4" and do a simple arithmetic operation: 9 + 3 / 4 = 9.75
I wrote this method for this work:
private double DoWork(string data)
{
double final = 0;
foreach (string s in data.Split(' '))
{
if (s.Contains('/'))
{
final += double.Parse(s.Split('/')[0]) / double.Parse(s.Split('/')[1]);
}
else
{
double tryparse = 0;
double.TryParse(s, out tryparse);
final += tryparse;
}
}
return final;
}
Is it useful to you ?
I think you can also use the dynamically compiling code
static void Main(string[] args)
{
var value = "9 3/4";
value = value.Split(' ')[0] + "d + " + value.Split(' ')[1] + "d";
var exp = " public class DynamicComputer { public static double Eval() { return " + value + "; }}";
CodeDomProvider cp = new Microsoft.CSharp.CSharpCodeProvider();
ICodeCompiler icc = cp.CreateCompiler();
CompilerParameters cps = new CompilerParameters();
CompilerResults cres;
cps.GenerateInMemory = true;
cres = icc.CompileAssemblyFromSource(cps, exp);
Assembly asm = cres.CompiledAssembly;
Type t = asm.GetType("DynamicComputer");
double d = (double)t.InvokeMember("Eval",
BindingFlags.InvokeMethod,
null,
null,
null);
Console.WriteLine(d);
Console.Read();
}
Solution below won't work for negative fractions. Can be improved by changing
//is it a valid fraction?
if (denominator != 0)
{
d = whole + (numerator / denominator);
}
to
//is it a valid fraction?
if (denominator != .0)
{
var sign = Math.Sign(whole);
d = whole + sign*(numerator/denominator);
}

Categories