I have the following code to convert a very long numeric string.
using System;
class MainClass {
public static void Main (string[] args) {
string longString = "1000000000000000000000000000001";
double convertedString = Double.Parse(test);
Console.WriteLine(test2);
}
}
However, convertedString is outputted in scientific notation:
1E+30
Is there a way to retain the exact value of the double when I convert it from a string?
The format of the output and the precision of the variable itself have nothing to do with each other. You can get the format you want by changing the format string, e.g.
Console.WriteLine("{0:N}", test1);
As for the precision of the variable, you should be aware that floating point numbers are not precise. And your number is about ten digits too long to fit into a long.
You will either need to store that number as a custom data type or, if it is just an identifier and not actually a number on which you need to perform math, simply store it as a string.
Related
I have a file with various characters and either words as well as numbers. These numbers can be integers like a 1 or 12 (as an example) or they have a comma and countless digits after the comma.
for example:
",{"n":"Box","p":[-4.0,4.0,0.0],"r":[270.0,0.0,0.0],"s":[1.0,1.000006,1.000006],"c":[0.448529363,0.4280135,0.412251264],"m":"wood_14"}"
The file is read with File.ReadAllText and then passed to NewtonsoftJson via JsonProperty accordingly
for example:
[JsonProperty("s")]
public double[] Scale
{
get;
set;
}
For example, with Scale, I want to limit the decimal places to a maximum of 5 digits.
Is this possible and if so, how?
I have been trying for days with different things, but nothing has worked yet.
My idea was to intervene in the string I build first before passing that to Json there. But unfortunately this does not work. I tried it with regular expression like Notepadd++ makes for example.
(edit)
I don't know if you want it to serialize or deserialize. So I made code for both cases. You have to leave one variant or another
public class a
{
private double[] val;
[JsonProperty("s")]
public double[] Scale
{
get { return val;
// or
val?.Select(v => Math.Round(v, 5)).ToArray(); }
set {
val=value;
//or
val = value?.Select(v => Math.Round(v, 5)).ToArray();
}
}
}
if you want it in many properties you can make it as a function
double.ToString() will do it.
const double d = 0.123456789;
string s = d.ToString("G5");
Console.WriteLine(s);
That outputs 0.12346, showing that it rounds the 5 to 6.
Documentation for Double.ToString shows much more detailed examples of how to format numbers.
The number format (i.e. decimal separator) is culture-specific. If you want to use the current culture, then the above will work. If you always want a comma as the decimal separator, you'll have to call the overload that accepts an IFormatProvider for the specific culture.
I have a simple class that contains a property Format which is set to any given format specifier. I then use the property of this class to, as the name suggest, format the string.
Take the following example:
public class FormatDefinition {
public string Format { get; set; }
}
class Program {
static void Main() {
var formatDefinition = new FormatDefinition {
Format = "N"
};
var number = 20.5;
var formatOne = string.Format("{0:" + formatDefinition.Format + "}", number);
var formatTwo = string.Format("{0:formatDefinition.Format}", number);
var formatThree = $"{number:formatDefinition.Format}";
Console.WriteLine(formatOne); // 20.5
Console.WriteLine(formatTwo); // formatDefinition21Format
Console.WriteLine(formatThree); // formatDefinition21Format
Console.ReadLine();
}
}
Can someone please explain why formatTwo and formatThree have a result of formatDefinition21Format? It seems the period . is replaced by the formatted number.
You are specifying a custom numeric format string consisting of the string "formatDefinition.Format".
This is taken to mean constant string "formatDefinition" followed by the decimal point (and therefore the entire number goes here) followed by constant string "Format".
The number is rounded to zero decimal places because there are no digits specified after the decimal point.
The string formatDefinition.Format is not interpreted as C# code.
According to the documentation for Custom Number Format Strings:
For fixed-point format strings (that is, format strings that do not
contain scientific notation format characters), numbers are rounded to
as many decimal places as there are digit placeholders to the right of
the decimal point.
It's because you have a decimal point with no digit placeholders to its right. You're telling it to round the number to zero decimal places - in other words, round to the nearest whole number.
These are all functionally the same - all return a22b.
string.Format("{0:a.b}", 21.5);
string.Format("{0:a0b}", 21.5);
string.Format("{0:a0.b}", 21.5);
Here's a DotNetFiddle.
I have code to remove trailing zeros from a value before presenting it to the UI, however I have found that in some cases, instead of removing the zeros it alters the value.
eg: 123.400000000000000000 becomes 123.40000000000001
the code I am using is:
string value = "123.400000000000000000";
value = double.Parse(value).ToString("G29");
Does anyone know why this is happening, and how I can alter my code so it shows '123.4' instead.
It's because you're turning it into a double and, as everyone who's spent time dealing with floating point values will know, double precision values are not infinite precision values. The value selected is as close as it can get to what you provide but that's not always exactly what you want.
If you have a numeric-style string that you want to strip trailing zeros from, why don't you just strip the trailing zeros from it, with something like:
if (s.Contains(".")) {
Regex regex = new Regex("\\.?0*$");
s = regex.Replace(s,"");
}
The check for a . character is to ensure you don't strip trailing zeros off a number like 1000. Once you know there's a decimal point in there, zeros (and the decimal point itself if it's _all zeros after that) can be stripped off the end with impunity. You can see it in action in the following complete console program:
using System;
using System.Text.RegularExpressions;
namespace ConsoleApplication1
{
class Program
{
static string StripZ(string s)
{
if (s.Contains("."))
{
Regex regex = new Regex("\\.?0*$");
s = regex.Replace(s, "");
}
return s;
}
static void Main(string[] args)
{
Console.WriteLine(StripZ("123.400"));
Console.WriteLine(StripZ("3.0"));
Console.WriteLine(StripZ("7."));
Console.WriteLine(StripZ("1000"));
Console.ReadLine();
}
}
}
The output of that program is:
123.4
3
7
1000
The problem is that 123.4 is not exactly representable in a binary floating point data type. The closest double precision value is:
123.40000 00000 00005 68434 18860 80801 48696 89941 40625
The ToString method is rounding that to
123.40000 00000 0001
You should use a decimal data type instead of a binary data type. For instance:
string value = "123.400000000000000000";
value = decimal.Parse(value).ToString("G29");
However, if you are really starting with a string, and just wish to trim trailing zeros then it would perhaps be more prudent to do that using text processing.
I'm trying to convert a number so it looks like the formatting in money.
I need to take 258000 and make it 2,580.00 or 25000 and make it 250.00 or 360 and make it 3.60
This is what I'm using but it's adding the ".00" at the end of all numbers making 2500 2500.00 but it should be 25.00.
Value = string.Format("{0:##,###.00}", Convert.ToDecimal(Value));
It seems to me that you're just missing the fact that you can divide the user's input by 100 after parsing it:
using System;
class Program
{
static void Main(string[] args)
{
string input = "2500";
decimal cents = decimal.Parse(input); // Potentially use TryParse...
decimal dollars = cents / 100m;
string output = dollars.ToString("0.00");
Console.WriteLine(output); // 25.00
}
}
Note that there are complicated cultural rules around how currency values should be displayed - I would suggest using the C format specifier, using a CultureInfo which is like whatever the users are expecting, but with the NumberFormatInfo.CurrencySymbol set to an empty string.
You should also consider which culture to use when parsing the user's input - it can significantly affect the results if they decide to use grouping separators or decimal separators. Will they always be entering an integer? If so, parse it as an integer too.
double valueOriginal = 260;
Response.Write( (valueOriginal / 100).ToString("C"));
260 = (206/100)
then
(260/100).ToString("C");
I need to take a string object and convert it to a decimal to 4 dp.
So for example:
string val = "145.83011";
decimal sss = Math.Round(Convert.ToDecimal(val), 4);
bring back 145.8301 - good
However:
string val = "145.8300";
decimal sss = Math.Round(Convert.ToDecimal(val), 4);
brings back 145.83
I need it to be 145.8300
I need it in a decimal format so can't use string format options.
Thanks
rob
One option would be to use string manipulation three times:
Parse the original text to a decimal value (this will preserve the original number of decimal places)
Use string formatting to end up with a string with exactly 4 decimal places. (Math.Round ensures there are at most 4DP, but not exactly 4DP.)
Parse the result of the formatting to get back to a decimal value with exactly 4DP.
So something like this:
public static decimal Force4DecimalPlaces(string input)
{
decimal parsed = decimal.Parse(input, CultureInfo.InvariantCulture);
string intermediate = parsed.ToString("0.0000", CultureInfo.InvariantCulture);
return decimal.Parse(intermediate, CultureInfo.InvariantCulture);
}
I recoil from using string conversions like this, but the alternatives are relatively tricky. You could either get the raw bits, split out the different parts to find the mantissa and scale, then adjust appropriately... or you could potentially work out some sequence of arithmetic operations to get to the right scale. (Jeppe's approach of multiplying by 1.0000m may well be entirely correct - I just don't know whether it's documented to be correct. It would at least be worth adding in appropriate tests for the sorts of numbers you expect to see.)
Note that the above code will perform round up on halves, as far as I can tell, so 1.12345 will be converted to 1.1235 for example.
Sample with output in comments:
using System;
using System.Globalization;
class Test
{
static void Main()
{
Console.WriteLine(Force4DecimalPlaces("0.0000001")); // 0.0000
Console.WriteLine(Force4DecimalPlaces("1.000000")); // 1.0000
Console.WriteLine(Force4DecimalPlaces("1.5")); // 1.5000
Console.WriteLine(Force4DecimalPlaces("1.56789")); // 1.5679
}
public static decimal Force4DecimalPlaces(string input)
{
decimal parsed = decimal.Parse(input, CultureInfo.InvariantCulture);
string intermediate = parsed.ToString("0.0000", CultureInfo.InvariantCulture);
return decimal.Parse(intermediate, CultureInfo.InvariantCulture);
}
}
Both Convert.ToDecimal and decimal.Parse do preserve trailing zeroes in the string (a System.Decimal can have at most 28-29 digits in total, so in most cases there's still room for all the trailing zeroes).
And Math.Round(..., 4) preserves trailing zeroes up to the fourth place after the decimal period.
Therefore the premise of the question is wrong. Your example does bring back what you want.
In any case, consider specifying the overload that takes in an IFormatProvider as well, and give CultureInfo.InvariantCulture as argument. Then the conversion is independent of the local culture.
If instead you want to handle strings like "145.83" and append trailing zeroes that were not in the string, use:
string val = "145.83";
decimal sss = Math.Round(
decimal.Parse(val, CultureInfo.InvariantCulture) * 1.0000m,
4);
Epilog: If you don't like multiplying and dividing by numbers like 1.0000m, use decimal.GetBits to get the internal representation. Adjust the integer "part" by multiplying or dividing by the appropriate power of ten, and adjust the scale "part" by subtracting or adding the corresponding number. The scale counts the number of places to move the decimal point to the left, starting from the 96-bit integer.