rounding to the best unit without losing precision - c#

I receive a decimal number with a maximum of 4 digits after the "." and I know this number is in milligram.
I have to find the best matching unit (milligram, gram, kilogram) for the number.
for an example if I receive
edited
116000000.0000 milligram, it's going to return 116.0000 kilogram
66990000.0000 milligram, it's going to return 66.9900 kilogram
49000010.0000 milligram, it's going to return 49000.0100 g
49000000.0100 milligram, it's going to return 49000000.0100 milligram
1001 milligram, it's going to return 1.0010 gram
1010 milligram, it's going to return 1.0100 gram
1000 milligram, it's going to return 0.0010 kilogram
1100 milligram, it's going to return 0.0011 kilogram
135005 milligram, it's going to return 135.0050 gram
and last sample 10013500 milligram, it's going to return 10.0135 kilogram
I'm currently using this code, which I think look/is ugly and can fail
Dim temp As Decimal
Dim u = New List(Of Integer)(New Integer() {1, 1000, 1000000})
For i = 0 To u.Count - 1
temp = CDec(qty / u(i))
If (temp * 10000) - Math.Truncate(temp * 10000) <> 0 AndAlso (temp * 10000) - Math.Truncate(temp * 10000) < 1 Then
temp = CDec(qty / u(i - 1))
Exit For
End If
Next
qty = temp
is there a better/nicer way of doing what I do?
edit for precision
the input can be any decimal between 0.0001 and maximum that a decimal can accept in .net
the output need to be rounded to the best unit with a maximum of 4 digits after "." without losing any precision

Gen the numbers and choose the suitable one.
public static decimal FormatDecimal(decimal i)
{
decimal milli = i;
decimal grams = decimal.Round(i / 1000m, 4);
decimal kilo = decimal.Round(grams / 1000m, 4);
if (kilo * 1000 * 1000 == milli)
{
return kilo;
}
if (grams * 1000 == milli)
{
return grams;
}
return milli;
}
And to test:
public static void FormatDecimalTest()
{
if (FormatDecimal(116000000.0000m) == 116.0000m)
Console.WriteLine("ok1");
if (FormatDecimal(66990000.0000m) == 66.9900m)
Console.WriteLine("ok2");
if (FormatDecimal(49000010.0000m) == 49000.0100m)
Console.WriteLine("ok3");
if (FormatDecimal(49000000.0100m) == 49000000.0100m)
Console.WriteLine("ok4");
if (FormatDecimal(1001m) == 1.0010m)
Console.WriteLine("ok5");
if (FormatDecimal(1000m) == 0.0010m)
Console.WriteLine("ok6");
if (FormatDecimal(1100m) == 0.0011m)
Console.WriteLine("ok7");
if (FormatDecimal(1100m) == 0.0011m)
Console.WriteLine("ok8");
if (FormatDecimal(135005m) == 135.0050m)
Console.WriteLine("ok9");
if (FormatDecimal(10013500m) == 10.0135m)
Console.WriteLine("ok10");
}
In your question, I see you used a loop over the various factors. Here's a looping solution that will find the first factor that does not lose precision.
public static decimal FormatDecimal(decimal i)
{
List<decimal> myFactors = new List<decimal>()
{ 1000m * 1000m, 1000m};
foreach (decimal conversionFactor in myFactors)
{
decimal result = decimal.Round(i / conversionFactor, 4);
if (result * conversionFactor == i)
{
return result;
}
}
return i;
}

Why don't you just use ifs? something like:
if (num > 1000000)
return string.format("{0.####} kg", num/1000000)
if (num > 1000)
return string.format("{0.####} g", num/1000);
return string.format("{0.####} mg", num);

I wouldn't be above doing a CStr on the number, counting the characters, removing all trailing zeros, counting the number again, and deciding on a unit based on the number of characters in your string. Then just divide the original number by the correct magnitude and append the unit.
Before doing that, though, you'd want to do a Truncate on the original and see if the returned value matches the original; then you just use mg.
Probably won't work any better than your code, but it might be easier to read. Maybe.

Your sample doesn't make too much sense, but your should go with something like this:
static string FormatWeight(double value)
{
if (value > 10000000) return (value / 10000000D).ToString("0.#### t");
if (value > 100000) return (value / 100000D).ToString("0.#### kg");
if (value > 1000) return (value / 1000D).ToString("0.#### g");
return value.ToString("0.#### mg");
}

would you not be better either implementing or using a unit library for the conversions, then formatting the results afterwards?
some projects here and here, although I can't vouch for the quality of any of it...
and java one discussed here

so if I understood correctly, any argument ARG which comes with a fraction <> 0 will stay as is and expressed in mg ... this should be easy to code
If ARG <> Int(ARG) Then
' Return ARG
Endif
anything without a fraction should be converted to the most appropriate unit (mg, g, dag, kg, t, etc). So for these we need to to look at the argument as a string and count the "0"es from the back-end and see from there how often we may divide by 10 without loosing numeric precision.
In your first example we count 6 Zeroes from the backend, so we could safely divide by 10^(6+4) to get not more than 4 fractional digits (which is more than we actually need).
In your last example we count 2 "0"es from the back, so we can safely divide by 10^(2+4).
So if the "save division power" is >=6, divide by 10^6 and express in kg
if the "save division power is between 5 and 3, divide by 10^3 and express in g, below 3 leave as mg.
Hope that helps.

Related

Check if a string is percentage value

I'm trying to write this in C#. The requirement is very straightforward - check if a string input is a value within the range from 0 to 100.
I want to make sure the string is either an integer value in the range of 0 to 100 or
a double that's within the same range as well.
So for example, these are the accepted values:
0
50
100
0.1
50.7
100.0
I checked the double.parse method here but not sure if it's the one I'm looking for: https://learn.microsoft.com/en-us/dotnet/api/system.double.tryparse?view=net-7.0#system-double-tryparse(system-string-system-iformatprovider-system-double#)
The reason is that it can also parse string like this one: 0.64e2 (which is 64)
Is this something that can be achieved with built-in library already?
Wrote you a little snippet:
// C# function to check if string is a percentage between 0 and 100
public static bool IsPercentage(string s)
{
// regex check if s is a string with only numbers or decimal point
if (Regex.IsMatch(s, #"^\d+\.?\d*$"))
{
double d = Convert.ToDouble(s);
return d >= 0 && d <= 100;
}
return false;
}
Also returns false if the string contains % or has exponential (e).
if my understanding of the Q was correct and exponential representations like mentioned "0.64e2" is unwanted:
static bool IsPercentage(string s)
{
if (Single.TryParse(s, NumberStyles.AllowLeadingSign |
NumberStyles.AllowDecimalPoint, NumberFormatInfo.InvariantInfo, out Single n))
return n >= 0 && n <= 100;
return false;
}

Calculating Lucas Sequences efficiently

I'm implementing the p+1 factorization algorithm. For that I need to calculate elements of the lucas sequence which is defined by:
(1) x_0 = 1, x_1 = a
(2) x_n+l = 2 * a * x_n - x_n-l
I implemented it (C#) recursively but it is inefficient for bigger indexes.
static BigInteger Lucas(BigInteger a, BigInteger Q, BigInteger N)
{
if (Q == 0)
return 1;
if (Q == 1)
return a;
else
return (2 * a * Lucas(a, Q - 1, N) - Lucas(a, Q - 2, N)) % N;
}
I also know
(3) x_2n = 2 * (x_n)^2 - 1
(4) x_2n+1 = 2 * x_n+1 * x_n - a
(5) x_k(n+1) = 2 * x_k * x_kn - x_k(n-1)
(3) and (4) should help to calculate bigger Qs. But I'm unsure how.
Somehow with the binary form of Q I think.
Any help is appreciated.
Here one can see how to find Nth Fibbonaci number using matrix powering with matrix
n
(1 1)
(1 0)
You may exploit this approach to calculate Lucas numbers, using matrix (for your case x_n+l = 2 * a * x_n - x_n-l)
n
(2a -1)
(1 0)
Note that Nth power of matrix could be found with log(N) matrix multiplications by means of exponentiation by squaring
(3) x_2n = 2 * (x_n)^2 - 1
(4) x_2n+1 = 2 * x_n+1 * x_n - a
Whenever you see 2n, you should think "that probably indicates an even number", and similarly 2n+1 likely means "that's an odd number".
You can modify the x indices so you have n on the left (as to make it easier to understand how this corresponds to recursive function calls), just be careful regarding rounding.
3) 2n n
=> n n/2
4) it is easy to see that if x = 2n+1, then n = floor(x/2)
and similarly n+1 = ceil(x/2)
So, for #3, we have: (in pseudo-code)
if Q is even
return 2 * (the function call with Q/2) - 1
And for #4:
else // following from above if
return 2 * (the function call with floor(Q/2))
* (the function call with ceil(Q/2)) - a
And then we can also incorporate a bit of memoization to prevent calculating the return value for the same parameters multiple times:
Keep a map of Q value to return value.
At the beginning of the function, check if Q's value exists in the map. If so, return the corresponding return value.
When returning, add Q's value and the return value to the map.
The n-th Lucas number has the value:
Exponentiation by squaring can be used to evaluate the function. For example, if n=1000000000, then n = 1000 * 1000^2 = 10 * 10^2 * 1000^2 = 10 * 10^2 * (10 * 10^2 )^2. By simplifying in this way you can greatly reduce the number of calculations.
You can get some improvements (just a factor of a million...) without resorting to really fancy math.
First let's make the data flow a little more explicit:
static BigInteger Lucas(BigInteger a, BigInteger Q, BigInteger N)
{
if (Q == 0)
{
return 1;
}
else if (Q == 1)
{
return a;
}
else
{
BigInteger q_1 = Lucas(a, Q - 1, N);
BigInteger q_2 = Lucas(a, Q - 2, N);
return (2 * a * q_1 - q_2) % N;
}
}
Unsurprisingly, this doesn't really change the performance.
However, it does make it clear that we only need two previous values to compute the next value. This lets us turn the function upside down into an iterative version:
static BigInteger IterativeLucas(BigInteger a, BigInteger Q, BigInteger N)
{
BigInteger[] acc = new BigInteger[2];
Action<BigInteger> push = (el) => {
acc[1] = acc[0];
acc[0] = el;
};
for (BigInteger i = 0; i <= Q; i++)
{
if (i == 0)
{
push(1);
}
else if (i == 1)
{
push(a);
}
else
{
BigInteger q_1 = acc[0];
BigInteger q_2 = acc[1];
push((2 * a * q_1 - q_2) % N);
}
}
return acc[0];
}
There might be a clearer way to write this, but it works. It's also much faster. It's so much faster it's kind of impractical to measure. On my system, Lucas(4000000, 47, 4000000) took about 30 minutes, and IterativeLucas(4000000, 47, 4000000) took about 2 milliseconds. I wanted to compare 48, but I didn't have the patience.
You can squeeze a little more out (maybe a factor of two?) using these properties of modular arithmetic:
(a + b) % n = (a%n + b%n) % n
(a * b) % n = ((a%n) * (b%n)) % n
If you apply these, you'll find that a%N occurs a few times so you can win by precomputing it once before the loop. This is particularly helpful when a is a lot bigger than N; I'm not sure if that happens in your application.
There are probably some clever mathematical techniques that would blow this solution out of the water, but I think it's interesting that such an improvement can be achieved just by shuffling a little code around.

How can I define comparison has to be an int?

Here a short code for the thing which is already coded:
if (str.Length % 3 != 0)
Now my question is, how can I define, that if str.Length % 3 = int it has to do something?
Here an example:
123456789123 / 3 = int...
I know, the Syntax I used isn't correct, but it's because I don't know how to do it.
You would also help me, if you told me, what the "opposite" of if (str.Length % 3 != 0) is.
Thanks for helping.
It will be an int no matter what with the code you have provided.
Reason: int / int = int ... any decimal values will be truncated (not rounded). C# does not automatically turn numbers into float or double if there is need for it. You need to do type conversion of that nature explicitly.
I think you may have also confused modulo % and divide /. If you want to know if there is no remainder which means that the number coming out of the computation is an Integer do the if (str.Length % 3 != 0) you put in the code.... I assume you're looking for something like this
if (str.Length % 3 != 0)
{
int num = str.Length / 3;
//Now do something with your int version of num
}
else
{
double num = str.Length / (double)3;
//Now do something with your double version of num
}
By casting 3 which is an int to double the resulting number will be a double, if you don't do that you will get a truncated integer value then implicitly casted to a double and stored in num.
The statement str.Length % 3 always results in an integer. What you need is probably just a simple negation of this statement, that will tell you, that there is a remainder...
Negation of != is of course ==
try this
if ((str.Length % 3).GetType() == typeof(int))
{
//is integer
}

Fermat primality test

I have tried to write a code for Fermat primality test, but apparently failed.
So if I understood well: if p is prime then ((a^p)-a)%p=0 where p%a!=0.
My code seems to be OK, therefore most likely I misunderstood the basics. What am I missing here?
private bool IsPrime(int candidate)
{
//checking if candidate = 0 || 1 || 2
int a = candidate + 1; //candidate can't be divisor of candidate+1
if ((Math.Pow(a, candidate) - a) % candidate == 0) return true;
return false;
}
Reading the wikipedia article on the Fermat primality test, You must choose an a that is less than the candidate you are testing, not more.
Furthermore, as MattW commented, testing only a single a won't give you a conclusive answer as to whether the candidate is prime. You must test many possible as before you can decide that a number is probably prime. And even then, some numbers may appear to be prime but actually be composite.
Your basic algorithm is correct, though you will have to use a larger data type than int if you want to do this for non-trivial numbers.
You should not implement the modular exponentiation in the way that you did, because the intermediate result is huge. Here is the square-and-multiply algorithm for modular exponentiation:
function powerMod(b, e, m)
x := 1
while e > 0
if e%2 == 1
x, e := (x*b)%m, e-1
else b, e := (b*b)%m, e//2
return x
As an example, 437^13 (mod 1741) = 819. If you use the algorithm shown above, no intermediate result will be greater than 1740 * 1740 = 3027600. But if you perform the exponentiation first, the intermediate result of 437^13 is 21196232792890476235164446315006597, which you probably want to avoid.
Even with all of that, the Fermat test is imperfect. There are some composite numbers, the Carmichael numbers, that will always report prime no matter what witness you choose. Look for the Miller-Rabin test if you want something that will work better. I modestly recommend this essay on Programming with Prime Numbers at my blog.
You are dealing with very large numbers, and trying to store them in doubles, which is only 64 bits.
The double will do the best it can to hold your number, but you are going to loose some accuracy.
An alternative approach:
Remember that the mod operator can be applied multiple times, and still give the same result.
So, to avoid getting massive numbers you could apply the mod operator during the calculation of your power.
Something like:
private bool IsPrime(int candidate)
{
//checking if candidate = 0 || 1 || 2
int a = candidate - 1; //candidate can't be divisor of candidate - 1
int result = 1;
for(int i = 0; i < candidate; i++)
{
result = result * a;
//Notice that without the following line,
//this method is essentially the same as your own.
//All this line does is keeps the numbers small and manageable.
result = result % candidate;
}
result -= a;
return result == 0;
}

Representing double values in the exponential format in C#

Need to display the values in the floating point format as well as in exponential format
if the value is greater or equal to 0.01 and less than or equal to 1000
display in the expotential format else display in the floating format
For eg : 3.230000000 is displayed as 3.23
0.00001 is displayed as 1E-05
But the problem with my code if number given is 1 then the number is displayed as 1.00.
if (dValue >= 0.01|| dValue <= 1000.0)
return (string.Format("{0:0.##E+00}", dValue));
else
return (string.Format("{0:F2}", dValue));
Please let me know how to check the number does not contain decimal values
Round the number to two decimal places and to an integer, and see if the results are "close enough":
if (dValue >= 0.01 && dValue <= 1000.0)
{
if (Math.Abs(Math.Round(dValue, 2) - Math.Round(dValue, 0)) < 0.005) {
return string.Format("{0:F0}", dValue);
else
return string.Format("{0:F2}", dValue);
}
else return (string.Format("{0:0.##E+00}", dValue));
The thing to note here is that (as always with floating point numbers) the comparison between the two rounded results should not be an equality comparison.
Replace your last line
return (string.Format("{0:F2}", dValue))
to
return (string.Format("{0:0.##}", dValue))
Consider simply using G format.
Or use Math.Truncate to get integral part, that see if it ie the same as original number (need to take into account output format precision to do comparison with desider eps, probably 0.005 in your case).
Too much time. :)
You will get 2 digits maximum with values like 3.234.
class Program
{
static void Main(string[] args)
{
Console.WriteLine(Format(0.00001));
Console.WriteLine(Format(1));
Console.WriteLine(Format(3.2));
Console.WriteLine(Format(3.22));
Console.WriteLine(Format(3.256));
Console.ReadLine();
}
static string Format(double dValue)
{
if (dValue >= 0.01 && dValue <= 1000.0)
{
int temp = (int)Math.Round(dValue * 100);
if (temp % 100 == 0)
return ((int)dValue).ToString();
else if (temp % 10 == 0)
return (string.Format("{0:F1}", dValue));
else
return (string.Format("{0:F2}", dValue));
}
else
return (string.Format("{0:0.##E+00}", dValue));
}
}
gives
1E-05
1
3,2
3,22
3,26
Probably there are cleaner solutions?!

Categories