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
Related
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.
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.
I'm trying to write a piece of code in C# to find the number digits of a integer number, the code works perfectly for all numbers (negative and positive) but I have problem with 10, 100,1000 and so on, it shows one less digits than the numbers' actual number of digits. like 1 for 10 and 2 for 100..
long i = 0;
double n;
Console.Write("N? ");
n = Convert.ToInt64(Console.ReadLine());
do
{
n = n / 10;
i++;
}
while(Math.Abs(n) > 1);
Console.WriteLine(i);
Your while condition is Math.Abs(n) > 1, but in the case of 10, you are only greater than 1 the first time. You could change this check to be >=1 and that should fix your problem.
do
{
n = n / 10;
i++;
}
while(Math.Abs(n) >= 1);
Use char.IsDigit:
string input = Console.ReadLine();
int numOfDigits = input.Count(char.IsDigit);
What's wrong with:
Math.Abs(n).ToString(NumberFormatInfo.InvariantInfo).Length;
Indeed, converting a number to a string is computationally expensive compared to some arithmetic, but it is hard to deal with negative nubers, overflow,...
You need to use Math.Abs to make sure the sign is not counted, and it is a safe option to use NumberFormatInfo.InvariantInfo so that for instance certain cultures that use spaces and accents, do not alter the behavior.
public static int NumDigits(int value, double #base)
{
if(#base == 1 || #base <= 0 || value == 0)
{
throw new Exception();
}
double rawlog = Math.Log(Math.Abs(value), #base);
return rawlog - (rawlog % 1);
}
This NumDigits function is designed to find the number of digits for a value in any base. It also includes error handling for invalid input. The # with the base variable is to make it a verbatim variable (because base is a keyword).
Console.ReadLine().Replace(",", String.Empty).Length;
this will count all the char in a string
int amount = 0;
string input = Console.ReadLine();
char[] chars = input.ToArray();
foreach (char c in chars)
{
amount++;
}
Console.WriteLine(amount.ToString());
Console.ReadKey();
I am using a generic class to convert an INT to a X base:
BaseX basex = new BaseX("abcdefghijklmnopqrstuvwxyz");
var a = basex.ToBaseX(1002);
var b = basex.FromBaseX("aghe");
And the BaseX class is as follows:
public class BaseX {
private readonly string _digits;
public BaseX(string digits) {
_digits = digits;
}
public string ToBaseX(int number) {
var output = "";
do {
output = _digits[number % _digits.Length] + output;
number = number / _digits.Length;
}
while (number > 0);
return output;
}
public int FromBaseX(string number) {
return number.Aggregate(0, (a, c) => a * _digits.Length + _digits.IndexOf(c));
}
}
I am using the lowercase base but I can use any other base.
Is it possible to make the output in the base X always the same length?
I think I should use "Multiplicative Inverse" and some similar process with mapping and encoding but I am not sure how to do this ...
Could I get some help to create this?
Basically, my objective is instead of creating random fixed lenght codes to use in promotions or in ID obfuscation just create a fixed length of an INT (The ID on the database).
Thank You,
Miguel
If I understand you correctly you want to pad the generated value with "zeroes". E.g. if you were using plain numbers and you wanted an ID of length 10 and the ID was 1234 the padded ID would be 0000001234.
The simplest way is to pad the generated value. You can add a new method to the BaseX class:
public string ToBaseX(int number, int width) {
var output = ToBaseX(number);
return output.PadLeft(width, _digits[0]);
}
With this method basex.ToBaseX(1002, 10) returns
aaaaaaabmo
and basex.FromBaseX("aaaaaaabmo") returns
1002
In the comments you indicate that the resulting string aaaaaaabmo does not seem very random. But then you can use the approach that Eric Lippert describes in the article A practical use of multiplicative inverses that you are referring to.
First you need to pick an upper limit to the numbers you want to obfuscate (and this number should fit into a 32 bit integer). Eric Lippert uses 1000000000 (1 billion). You then need to pick a number less than the limit that is coprime with the limit (e.g. they do not share any prime factors). Eric Lippert chooses 387420489 (and explains that any number that ends in 9 will be coprime with a number that is a power of 10). You then need to calculate the modular multiplicative inverse of this number, e.g. a number inverse-x that satisfies the following condition:
387420489 * inverse-x = 1 (mod 1000000000)
You can use the extended Euclidian algorithm for this calculation for instance using an online calculator. The modular multiplicative inverse is 513180409.
To obfuscate you number you can use this code (to avoid overflow it is important to perform the calculation using 64 bit integers):
var value = 1002;
var m = 1000000000L;
var x = 387420489L;
var inverseX = 513180409L;
var encoded = value*x%m;
var decoded = encoded*inverseX%m;
For this particular calculation encoded is 195329978.
If you want to use the lower case letters to represent the obfuscated number you can use your BaseX class to convert the number to base 26. You can compute the maximum letters required to represent any number below 1 billion:
Math.Log(1000000000)/Math.Log(26) = 6.36054383137796
This means that you need no more than 7 letters to represent your number.
I have combined all this into two simple methods using some constants you can easily customize:
static class Obfuscator {
const Int64 modulo = 1000000000L;
const Int64 coprime = 280619659L;
const Int64 inverseCoprime = 687208739L;
const String digits = "abcdefghijklmnopqrstuvwxyz";
const Int32 maxDigits = 7; // Math.Log(modulo)/Math.Log(digits.Length) rounded up.
public static String Obfuscate(Int32 originalValue) {
if (originalValue >= modulo || originalValue < 0)
throw new ArgumentOutOfRangeException();
var value = (Int32) (originalValue*coprime%modulo);
var buffer = new Char[maxDigits];
var i = maxDigits;
do {
buffer[--i] = digits[value%digits.Length];
value /= digits.Length;
} while (value > 0);
while (i > 0)
buffer[--i] = digits[0];
return new String(buffer);
}
public static Int32 Deobfuscate(String obfuscatedValue) {
if (String.IsNullOrEmpty(obfuscatedValue))
throw new ArgumentException();
var value = obfuscatedValue
.Aggregate(0, (a, c) => a*digits.Length + digits.IndexOf(c));
return (Int32) (value*inverseCoprime%modulo);
}
}
Only detail to be aware of is that 0 is obfuscated into aaaaaaa. For any number between 1 and 999999999 (inclusive) you get what looks like a random string of 7 characters.
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);
}