Large Decimal Number Parse - c#

I know this has some answers but not exactly what I'm looking for.
I have an application with a custom scripting language for file formats where numbers can be added, subtracted, etc...
One part will produce decimal,hex conversion and I was able to use the BigInteger class which is nice because I don't have to worry about large values.
For math operations though I am stuck using a Decimal and I would like to know if anyone has any suggestions for something like BigInteger that I can use for Decimal. I have seen BigRational but it doesn't look like it will fit.
Here is the code snippet where it's used. The asdecimal probably looks stupid but it's just decimal parse where zero is returned if invalid.
private string Subtract(StringReader reader, string text)
{
string value = reader.ReadToEnd();
value = Evaluate(value);
var a = text.AsDecimal();
var b = value.AsDecimal();
return (a - b).ToString();
}
To make this more clear. This function can handle any conceivable situation because of BigInteger
private string HexToDec(string value)
{
try
{
var input = this.Evaluate(value);
var number = BigInteger.Parse(input, System.Globalization.NumberStyles.HexNumber);
return number.ToString();
}
catch (Exception)
{
return "INVALID_HEX_NUMBER";
}
}
I would like subtract tot be as flexible. If it's not possible, that is fine.

Related

How to compare the elements of two string lists in C# and see if any element is convertible to double

Hello I'm making a quiz app and I want to compare user answers to the correct answers. I'm planning to do that with two string lists as I collect the answers in strings and I also have the correct answers in strings.
The problem that I'm facing is that half of the questions are True/False questions so the answers are in "True" or "False" strings, the other half are questions where a calculation has to be performed, therefore the answer is a number/double which I store as a string.
I want to give a range of answer acceptance of 0.1 so if the correct answer is 22.5 an answer of 22.6 would still be considered correct. This, however, makes it impossible to compare the value of the "number" strings with the Equals() method.
So I'm ideally looking for an if statement where I want to say:
if the element is convertible to a double convert it and check if its value is the same as the correct answer or within the acceptance range
else, check if the element is equal to the correct answer
For now I have made a console app to try and solve this problem where I have defined the two lists which look like this:
static void Main(string[] args)
{
List<string> givenAnswers = new List<string>()
{
"True","False","True","False","True",
"60","50","2.321","0.8","1.55"
};
List<string> correctAnswers = new List<string>()
{
"True","False","False","True","False",
"70","20","1.231","0.5","1.25"
};
correctAnswers.ForEach(Console.WriteLine);
Console.ReadLine();
}
The main problem is that c# doesnt return false if the element is not convertible but gives error which breaks the program.
(I was previously making the comparison on my frontend - java script where an unsuccessful conversion would return false)
Let's extract a method to compare two answers:
private static bool IsCorrectAnswer(string answer,
string expectedAnswer,
double tolerance = 0.1) {
// Let's not be peevish and tolerate leading / trimming spaces,
// ignore cases i.e. let " TRUE " be equal to "True"
if (string.Equals(answer?.Trim(),
expectedAnswer?.Trim(),
StringComparison.OrdinalIgnoreCase))
return true;
// If we have two double values, let's to parse them and compare
// with provided tolerance
if (double.TryParse(answer, out var leftValue) &&
double.TryParse(expectedAnswer, out var rightValue))
return Math.Abs(leftValue - rightValue) <= tolerance;
//TODO: you may want to add support for other types (say, dates) here
return false;
}
I didn't get your string list of booleans and numbers, but the general check would look like this:
foreach (var answer in givenAnswers)
{
if (double.TryParse(answer, NumberStyles.Any, CultureInfo.InvariantCulture, out double answerVal) && answerVal == 0.8)
{
Console.WriteLine("Nailed it!");
}
}
I had to use "invariant culture" because in my country, 0.8 is written as "0,8" and thus "0.8" is parses to 8...
I wouldn't go into lengths about the "nearby" numbers, because it's very complicated. Comparing Floating Point Numbers, 2012 Edition
You can use double.TryParse to check if a string is parsable to a double and parse it at the same time when it is.
bool IsAcceptableAnswser(string givenAnswer, string correctAnswer)
{
if (double.TryParse(correctAnswer, out var correctNumber) && double.TryParse(givenAnswer, out var givenNumber))
{
// When the answers are doubles, use use the double values.
var diff = Math.Abs(correctNumber - givenNumber);
return diff <= 0.1;
}
else
{
// When the answers aren't doubles, use string.Equals.
return string.Equals(givenAnswer, correctAnswer);
}
Notes
I used string.Equals for simplicity, but you could of course use something else to be more permissive around casing.
You might also want to check the other overloads of double.TryParse if culture is an issue.
I used 0.1 directly for readability. It would be preferable to use a constant or receive it as parameter.
Try:
var convertible = int.TryParse("60", out_)

Why is TryParse the way round that it is?

I've been struggling to get my head around a natural way of using TryParse because I keep expecting it to work the other way around (i.e. to return the parsed value and emit the boolean for whether the input parsed).
For example, if we take a basic implementation of Parse, the return value is the parsed input:
int parsedValue = int.Parse(input);
This works fine until it gets a value that it can't parse, at which point it entirely reasonably throws an exception. To me, the option then is either to wrap the parse in something like a try-catch block to handle the exception and a condition to set a default, or just to use TryParse to let C# do all that for me. Except that's not how TryParse works. The above example now looks like this:
bool parseSucceeded = int.TryParse(input, out int parsedValue);
To get it to assign in the same way as Parse, I wrap it in a ternary conditional with parsedValue and a default value (in this case, 0) as the true and false results respectively:
int parsedValue = int.TryParse(input, out parsedValue) ? parsedValue : 0;
But I still feel like I'm missing the point with TryParse if I'm just working around its default behaviour like this. I've read Tim Schmelter's excellent answer in which he shows its internal workings, from which I can suppose that it returns the boolean because it's easier internally than passing it out at all the various places that it currently returns. But I'm not sure about this, and I'm not satisfied that I understand its intent correctly. I also tried reading the documentation for it, but the remarks don't clear up my confusion (I don't think they even make its differences with Parse clear enough, like the change in return type).
Am I understanding it correctly, or am I missing something?
Sure, it could have been implemented as
int TryParse(string input, out bool succeeded)
{
}
But as mentioned in a comment, the common use case for the function is:
string input;
int parsedValue;
if(int.TryParse(input, out parsedValue))
{
// use parsedValue here
}
With the signature you propose, that code would now be:
string input;
bool succeeded;
int parsedValue = int.TryParse(input, out succeeded)
if(succeeded)
{
// use parsedValue here
}
So there's more code for no functional benefit. Also, with your ternary operator, if the parse fails you just set a value of zero, which is unnecessary since the default value of it is 0. You could just do:
int parsedValue;
int.TryParse(input, out parsedValue);
If the parse fails, parsedValue will have a value of 0; (I also question if/how you distinguish between an actual result of 0 and a failed parse, but I'm sure you have a reason).
So there's no technical reason why the signature is the way it is; it's a design decision that is appropriate for the most common use cases.
Of course, now with tuples in C# 7 you could have:
(int parsedValue, bool succeeded) = int.TryParse(input);
but again there's little functional benefit and prevents you from inlining the TryParse in an if statement.
Because logically you would want to check that the TryParse succeeded before trying to use the out value.
So this is more concise:
if (int.TryParse(input, out int parsedValue)}
{
// Do something with parsedValue
}
Than this:
int parsedValue = int.TryParse(input, out bool succeded);
if (succeeded)
{
// Do something with parsedValue
}
I think, a large part of your confusion stems from the method name isn't named exactly right:
int parsedValue = int.Parse("42");
This makes perfect sense, give me the integeger representation of a string.
int parsedValue = int.TryParse(input);
This makes sense as an extension of the concept: Input might be '42' or 'Oswald', but if it's a number I want that number.
In 2020, I think a better name would be CanParse(string input, out int result).
It better matches style guides and naming conventions, where returning a bool should be named with Is, Has, or Can.
It better matches how we use TryParse 99% of the time:
if (int.CanParse(input, out int result))
{
return result * 10;
}
But where I feel the current name makes sense, is the problem I assume it was trying to solve: To get rid of the following boilerplate code:
int result;
bool hasValidNumber = false;
try
{
result = int.Parse(input);
hasValidNumber = true;
}
catch
{
// swallow this exception
}
if (hasValidNumber)
{
// do things with result
}
else
{
// use a default or other logic
}

Having trouble casting string to integer

I'm trying to convert the string "127.0" to an integer.
I tried this function:
int getInt(string numStr)
{
int result;
int.TryParse(numStr, out result);
return result;
}
But when I call it as int x = getInt("127.0"); then int.TryParse() sets result to 0.
When I rewrite the function like this:
int getInt(string numStr)
{
result=Convert.ToInt32(numStr);
return result;
}
the same getInt() call throws this exception:
Input string was not in a correct format.
The issue here is that "127.0" is not an integer, it's a floating point number. You will need to parse it using one of the other floating point types (i.e. double, float, Decimal, etc.).
You may want to consider either stripping off any values after the decimal point and attempting to parse it, or parsing it as another type and casting it as an integer :
int result = (int)Convert.ToDouble("1.270");
You could also take advantage of the Math.Truncate() function which would give you the integer portion of your value :
int result = (int)Math.Truncate(Convert.ToDouble("127.0"));
First off, you need to check the return value of int.TryParse(). If it returns false, then the string could not be converted.
Had you done that, you would see it returned false because 127.0 does not describe an integer value (it describes a floating point value).
Note that decimal.TryParse() would succeed here. You need to figure out if you need an integer or floating point value, and reject data that is incorrect.
An int cannot contain a decimal point; that makes it either a double, a float, or a decimal. Try to pull the number minus anything from the decimal point over to the right, like this:
int getInt(string numStr)
{
int result;
string[] splitup;
string number;
if (numstr.Contains('.'))
{
splitup = numstr.Split('.');
number = splitup[0];
int.TryParse(number, out result);
}
else
{
int.TryParse(numstr, out result);
}
return result;
}
Rion Williams is absolutely correct, IMHO.
Along with the fact that what you are parsing is not an integer, I'd personally use the TryParse method. Many of the .NET types have it, and it's quite a bit "safer" (it won't throw exceptions) than just parsing a string.
Example:
string stringValue = "127.0";
int intValue;
if(Int32.TryParse(stringValue, out intValue))
{
// return value
}
// handle the failure
If you don't like that, I'd wrap it in a try-catch...

Convert.ToInt32 user input array to int c#

I have the attached code which trys to find all 1s in an array input by the user.
The program asks the user to select the array size, then input a number of that size with some 1s in it. It then counts the number of 1s found.
I guess that the input the user gives is in the form of a string? So, if they input 12345 it would be a string with one 1 in it.
I am trying to convert the array to int32, though I don't think I fully understand why it has to be int32 either.
If somebody could help me understand this programs' workings and why I'm getting the following error I'd be thankful.
An unhandled exception of type 'System.FormatException' occurred in
mscorlib.dll Additional information: Input string was not in a correct
format.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace count1s
{
class Program
{
static void Main(string[] args)
{
int count = 0;
Console.WriteLine("Enter a number for the array length");
int limit = int.Parse(Console.ReadLine());
int[] array1s = new int[limit];
Console.WriteLine("Enter a number with some 1s in it");
for(int i=0; i<limit; i++)
{
array1s[i] = Convert.ToInt32(Console.ReadLine());
}
foreach (int number in array1s)
{
if (number == 1)
{
count++;
}
}
Console.WriteLine("The number of 1s in the array is: {0}", count);
Console.ReadLine();
}
}
}
You are getting this error because you are entering the array elements in one line.
If you enter one element on one line then program will work fine.
If you want to accept numbers on one line then you can use split function like
String []numbers = Console.ReadLine().Split(' ');
for (int i = 0; i < limit; i++)
{
array1s[i] = Convert.ToInt32(numbers[i]);
}
foreach (int number in array1s)
{
if (number == 1)
{
count++;
}
}
I don't think I fully understand why it has to be int32 either.
It doesn't have to be. That depends on your input. If the user enters a number small enough, it can also fit into a short (which is 16 bits), and you can parse the string into that.
why I'm getting the following error
Because you're trying to parse a string which isn't parse-able to a valid int value. If you're not sure the input is valid, you can use a method such as int.TryParse, which returns a boolean indicating the success or failure of the parsing:
int i = 0;
while (i < limit)
{
string value = Console.ReadLine();
int parsedValue;
if (!int.TryParse(value, out parsedValue))
{
Console.WriteLine("You've entered an invalid number. Please try again");
continue;
}
array[i] = parsedValue;
i++;
}
If you want to count all occurrences of 1, you can simply use Enumerable.Count which takes a predicate:
return array.Count(number => number == 1);
Use this as
for(int i=0; i<limit; i++)
{
int value;
var isNumber = int.TryParse(Console.ReadLine(), out value);
if(isNumber)
{
array1s[i] = value;
}
else
{
Console.WriteLine("Invalid value you have entered");
continue;
}
}
Well, now I feel like a bit of an idiot.
I tried some of your responses, thanks very much for that, and they are good. I went back and tried the code I originally posted as well and found that it does work. I just need to hit carriage return after each entry into the array.
I'll take a look at all of this properly later to find out what is going on.
Thanks again all - gotta say - was really surprised to get so many responses on here so quickly. Awesome!!
I just found a really good article on the Microsoft: DEV204x Programming with C# course I have started online. I think this will be helpful to all who follow with the same questions I had. Hopefully I'm not breaking any copyright laws or stackoverflow rules. It's a free course, so I doubt it.
Data Conversions
C# supports two inherent types of conversion (casting) for data types, implicit and explicit. C# will use implicit conversion where it can, mostly in the case when a conversion will not result in a loss of data or when the conversion is possible with a compatible data type. The following is an example of an implicit data conversion.
Converting from smaller to larger integral types:
int myInt = 2147483647;
long myLong= myInt;
The long type has a 64-bit size in memory while the int type uses 32-bits. Therefore, the long can easily accomodate any value stored in the int type. Going from a long to an int may result in data loss however and you should use explicit casting for that.
Explicit casts are accomplished in one of two ways as demonstrated with the following coe sample.
double myDouble = 1234.6;
int myInt;
// Cast double to int by placing the type modifier ahead of the type to be converted
// in parentheses
myInt = (int)myDouble;
The second option is to use the methods provided in the .NET Framework.
double myDouble = 1234.6;
int myInt;
// Cast double to int by using the Convert class and the ToInt32() method.
// This converts the double value to a 32-bit signed integer
myInt = Convert.ToInt32(myDouble);
You will find many other methods in the Convert class that cast to different integral data types such as ToBoolean(), ToByte(), ToChar(), etc.
The Convert.ToInt32() method can also be used to cast a string literal to a numeric data type. For example, you may have GUI-based application in which uses input data into text boxes. These values are string values when passed to the code in your application. Use of the above method to cast the string to numbers can help prevent exceptions in your code when trying to use the wrong data type in a specific area.
C# also provides another mechanism to deal with casting types. The use of the TryParse() method and Parse() methods can help with casting as well. These methods are attached to the types in C# rather than the Convert class. An example will help demonstrate.
// TryParse() example
bool result = Int32.TryParse(value, out number);
// Parse() example
int number = Int32.Parse(value);
In the TryParse() example, the method returns a Boolean result indicating if the conversion succeeded. In the Parse() example, if the conversion does not succeed, an exception will be thrown.

Formatting double as string in C#

I have a Double which could have a value from around 0.000001 to 1,000,000,000.000
I wish to format this number as a string but conditionally depending on its size. So if it's very small I want to format it with something like:
String.Format("{0:.000000000}", number);
if it's not that small, say 0.001 then I want to use something like
String.Format("{0:.00000}", number);
and if it's over, say 1,000 then format it as:
String.Format("{0:.0}", number);
Is there a clever way to construct this format string based on the size of the value I'm going to format?
Use Math.Log10 of the absolute value of the double to figure out how many 0's you need either left (if positive) or right (if negative) of the decimal place. Choose the format string based on this value. You'll need handle zero values separately.
string s;
double epislon = 0.0000001; // or however near zero you want to consider as zero
if (Math.Abs(value) < epislon) {
int digits = Math.Log10( Math.Abs( value ));
// if (digits >= 0) ++digits; // if you care about the exact number
if (digits < -5) {
s = string.Format( "{0:0.000000000}", value );
}
else if (digits < 0) {
s = string.Format( "{0:0.00000})", value );
}
else {
s = string.Format( "{0:#,###,###,##0.000}", value );
}
}
else {
s = "0";
}
Or construct it dynamically based on the number of digits.
Use the # character for optional positions in the string:
string.Format("{0:#,###,##0.000}", number);
I don't think you can control the number of decimal places like that as the precision of the double will likely mess things up.
To encapsulate the logic of deciding how many decimal places to output you could look at creating a custom formatter.
The first two String.Format in your question can be solved by automatically removing trailing zeros:
String.Format("{0:#,##0.########}", number);
And the last one you could solve by calling Math.Round(number,1) for values over 1000 and then use the same String.Format.
Something like:
String.Format("{0:#,##0.########}", number<1000 ? number : Math.Round(number,1));
Following up on OwenP's (and by "extension" tvanfosson):
If it's common enough, and you're on C# 3.0, I'd turn it into an extension method on the double:
class MyExtensions
{
public static string ToFormmatedString(this double d)
{
// Take d and implement tvanfosson's code
}
}
Now anywhere you have a double you can do:
double d = 1.005343;
string d_formatted = d.ToFormattedString();
If it were me, I'd write a custom wrapper class and put tvanfosson's code into its ToString method. That way you could still work with the double value, but you'd get the right string representation in just about all cases. It'd look something like this:
class FormattedDouble
{
public double Value { get; set; }
protected overrides void ToString()
{
// tvanfosson's code to produce the right string
}
}
Maybe it might be better to make it a struct, but I doubt it would make a big difference. You could use the class like this:
var myDouble = new FormattedDouble();
myDouble.Value = Math.Pi;
Console.WriteLine(myDouble);

Categories