I want with a given double number to return its "size" (known as |number|, or number of digit without the numbers after the dot), for example:
12.324654 -> 2
12 -> 2
0.99 -> 0
1.01 -> 1
901 -> 3
-0.99 -> 0
-9.999 -> 1
There must be a function is .net that I dont familiar with that does it..
Thanks.
Try log10(max(abs(number), 0.5)) + 1 rounded down.
Or, in actual C# syntax:
(int)(Math.Log10(Math.Max(Math.Abs(number), 0.5)) + 1)
OK, how does that work?
At first of all, p = log10(x) is the base-10 logarithm of x; that is to say, the value such that 10 raised to the p-th power (or 1 followed by p zeros) equals x. The logarithm essentially measures the length of the number, except that it's a smooth function of x:
(Note that, in languages that don't provide a base-10 logarithm function, we can always calculate it as log10(x) = log(x) / log(10), where log() is the logarithm function in any base.)
For example, we have
log10(1) = 0.0
log10(10) = 1.0
log10(100) = 2.0
log10(1000) = 3.0
but also e.g.:
log10(5) = 0.69897
log10(50) = 1.69897
log10(500) = 2.69897
log10(5000) = 3.69897
In general, n ≤ log10(x) < n+1 whenever 10n ≤ x < 10n+1.
Looking at the values above, it should be easy enough to see that, to get the number of base-10 digits in a whole number, we should round its base-10 logarithm down to the nearest whole number and add 1 (because we want the length of 10 to be 2, not 1).
However, there are a few more edge cases to consider:
First, the original questioner wanted the length of −x to equal the length of x. The logarithm is only defined for positive numbers, so we replace x by its absolute value to make it always positive.
Second, the original questioner also wanted the length of numbers between 0 and 1 to be zero. The logarithm, however, can take arbitrarily large negative values:
log10(0.1) = −1.0
log10(0.01) = −2.0
log10(0.001) = −3.0
log10(0.0001) = −4.0
and indeed, log10(0) = −∞. To satisfy this requirement, we simply make sure that the number whose length we calculate can never go below 0.5 by using the maximum of it and 0.5 as the input to log10(). (We could use any number between 0.1 and 1 as the cutoff, but 0.5 happens to be a nice round binary fraction.)
Also, we have to make sure to add +1 to the logarithm before rounding it, so that the number that we round is always non-negative. That's because (int) in C# actually rounds negative numbers up towards zero. For example, since log10(0.5) ≈ −0.3, the expression (int)Math.Log10(0.5) + 1 (rounding before addition) would evaluate to 0+1 = 1 rather than the expected 0.
((int)Math.Abs(12.324654)).ToString().Length
Math.Abs will convert to positive number (don't want to count the negative sign)
(int) will drop the digits following the decimal point
ToString() converts to a string ===> "12"
Length tells you how many characters there are
there is an edge case where (int)( some number ) == 0, where the length is going to give you 1-- you may not want this, so be aware of the possibility
now, what you COULD do is make this an extention method....
public static class Utils
{
public static int Size(this double n)
{
int i = (int)Math.Abs(n);
if ( i == 0 ) return 0;
return i.ToString().Length;
}
}
12.324654.Size() == 2;
You could do something like below to account for your 0 digits returning zero length
private static int CountAbsoluteDigits(double p) {
int absolute = (int)Math.Abs(p);
if (0 == absolute)
return 0;
else
return absolute.ToString().Length;
}
...
var length = CountAbsoluteDigits(12.324654);
This is the output I got with the numbers you supplied..
12.324654 -> 2
12 -> 2
0.99 -> 0
1.01 -> 1
901 -> 3
-0.99 -> 0
-9.999 -> 1
Stealing Quintin's format:
private static int CountAbsoluteDigits(double p) {
int ip = (int)p;
int answer = 0;
while (ip!=0) {
answer++;
ip/=10;
}
return answer;
}
No trick (e.g., abs(), if) required in this.
Courtsey Muad'Dib
int GetLength(double value){
return ((int)Math.Abs(value*10d)).ToString().Length - 1
}
Converting to integer and converting the result to a string will only work if the value is within the range of an int. If you need values above 2 billion, you'll either need to work with logs, or deal convert the double to a string.
static int GetLength(double d)
{
d = Math.Abs(d);
if (d < 1.0) return 0;
if (double.IsInfinity(d)) return int.MaxValue;
if (double.IsNaN(d)) return 0;
return (int)Math.Floor(Math.Log10(d)) + 1;
}
static int GetLength2(double d)
{
d = Math.Abs(d);
if (d < 1.0) return 0;
if (double.IsInfinity(d)) return int.MaxValue;
if (double.IsNaN(d)) return 0;
string s = d.ToString("E"); // returns a string in the format "1.012435E+001"
return int.Parse(s.Substring(s.Length - 3)) + 1;
}
static void Test(double d) { Debug.WriteLine(d + " -> " + GetLength(d) + ", " + GetLength2(d)); }
static void Main(string[] args)
{
Test(0);
Test(0.125);
Test(0.25);
Test(0.5);
Test(1);
Test(2);
Test(10);
Test(10.5);
Test(10.25);
Test(10.1243542354235623542345234523452354);
Test(999999);
Test(1000000);
Test(1000001);
Test(999999.111);
Test(1000000.111);
Test(1000001.111);
Test(double.MaxValue);
Test(double.MinValue);
Test(double.PositiveInfinity);
Test(double.NegativeInfinity);
Test(double.NaN);
Test(double.Epsilon);
}
Results:
0 -> 0, 0
0.125 -> 0, 0
0.25 -> 0, 0
0.5 -> 0, 0
1 -> 1, 1
2 -> 1, 1
10 -> 2, 2
10.5 -> 2, 2
10.25 -> 2, 2
10.1243542354236 -> 2, 2
999999 -> 6, 6
1000000 -> 7, 7
1000001 -> 7, 7
999999.111 -> 6, 6
1000000.111 -> 7, 7
1000001.111 -> 7, 7
1.79769313486232E+308 -> 309, 309
-1.79769313486232E+308 -> 309, 309
Infinity -> 2147483647, 2147483647
-Infinity -> 2147483647, 2147483647
NaN -> 0, 0
4.94065645841247E-324 -> 0, 0
Related
I'm dealing with the following assignment, and as I'm not very familiar with recursion I'm at a loss. I'd greatly appreciate it if someone with more experience could point me in the right direction.
The assignment reads as follows:
Write a console application that determines all combinations of '+' and '-' operators which can be put between natural numbers ranging from 1 to a given N >=2, so that the result of the expression is a given X number. If there is no possible combination, the application will output 'N/A'.
Ex:
For inputs:
6 //N
3 //X
The console will read:
1 + 2 + 3 - 4 - 5 + 6 = 3
1 + 2 - 3 + 4 + 5 - 6 = 3
1 - 2 - 3 - 4 + 5 + 6 = 3
Given the circumstances of the assignment, I'm not allowed to use any other directive than 'System'. I've found several versions of this 'Coin Change' problem, but mostly in C++ or Python and also quite different than my current assignment. I'm not asking anyone to do my assignment for me, I'm simply looking for some valid pointers so I know where to start.
This code sample should help you. You can adapt this recursion to your needs, since it only counts number of such combinations.
Take into account that this approach is quite slow, you can find some DP solutions that are much faster.
private static int Search(int start, int end, int cur, int searched)
{
if (start > end)
{
return Convert.ToInt32(cur == searched);
}
return Search(start + 1, end, cur + start, searched) + Search(start + 1, end, cur - start, searched);
}
static void Main(string[] args)
{
int result = Search(2, 6, 1, 3);
}
I would make a function (let's call it f) that takes 5 parameters: The current number, the end number (N), the desidered result (X), the formula so far and the result of the formula so far.
In the function you first test if the current number is the end number. If it is, then test if the result of the formula is the desired number. If it is, print the formula.
If you're not at the end yet, then call the function itself twice. Once where you add the next number and once where you subtract it.
The first call to the function would be
f(1, 6, 3, "1", 1). It would then call itself twice with
f(2, 6, 3, "1 + 2", 3) and
f(2, 6, 3, "1 - 2", -1)
Then it would continue like that until it reaches the calls with 6 numbers in the formula where it would check if the result is 3.
Hope that helps you get started.
This answer strives to be the pinnacle in the art of helping without helping.
Which is what was asked for.
So here, the complete albeit a bit obfuscated solution in a language, you might have never heard of. But if you think about what you see long enough, you might get an idea how to solve this in C#.
data Expr = Lit Integer | Add | Sub deriving(Show)
compute :: [Expr] -> Integer -> Integer
compute [] value = value
compute (Add : Lit x : rest) value = compute rest (value + x)
compute (Sub : Lit x : rest) value = compute rest (value - x)
compute (Lit x1 : Add : Lit x2 : rest) value = compute rest (value + x1 + x2)
compute (Lit x1 : Sub : Lit x2 : rest) value = compute rest (value + x1 - x2)
compute [Lit x] _ = x
solve :: Integer -> [Integer] -> [Expr] -> [[Expr]] -> [[Expr]]
solve goal [] current found
| goal == compute current 0 = current : found
| otherwise = found
solve goal (n:ns) current found =
solve goal ns (current ++ [Add, Lit n]) []
++ solve goal ns (current ++ [Sub, Lit n]) []
prettyFormula :: [Expr] -> String
prettyFormula f =
concat $ fmap (\xp -> case xp of
Lit n -> show n
Add -> "+"
Sub -> "-") f
With that loaded and with fmap prettyFormula (solve 3 [2..6] [Lit 1] []) in the REPL, you get your result:
["1+2+3-4-5+6","1+2-3+4+5-6","1-2-3-4+5+6"]
This question already has answers here:
Always return positive value
(9 answers)
Closed 5 years ago.
Where taking away a minus value i.e. 5 - (-5), we are working this out as 10, which yes, mathematically it is correct.
But in this case, our logic should treat each number as a positive and not minus negative numbers. It should be 5 - (-5) = 0 as per our requirement.
Other people have provided Math.Abs as a solution. I don't know whether this inlines Math.Abs or not... But measure the performance gain from something like this vs Math.Abs:
int d = X > 0 ? X : -X;
to verify that it's really worth it.
if Math.Abs throws an OverflowException. You can force this in the straight C# as well using checked arithmetic:
int d = X > 0 ? X : checked(-X);
I ran some quick tests on different methods you can use:
Math.Abs(i) 5839 ms Factor 1
i > 0 ? i : -i 6395 ms Factor 1.09
(i + (i >> 31)) ^ (i >> 31) 5053 ms Factor 0.86
Winner: ([only int] as you can't bitshift floating point numbers in C#):
public static int ConvertToPositive(int i) {
return (i + (i >> 31)) ^ (i >> 31);
}
ConvertToPositive(-5); // 5
Try Math.Abs this will solve the purpose.
So before applying any arithmetic operation you should apply Math.Abs(value) which will convert your negative value to positive.
class Program
{
static void Main()
{
//
// Compute two absolute values.
//
int value1 = -1000;
int value2 = 20;
int abs1 = Math.Abs(value1);
int abs2 = Math.Abs(value2);
//
// Write integral results.
//
Console.WriteLine(value1);
Console.WriteLine(abs1);
Console.WriteLine(value2);
Console.WriteLine(abs2);
}
}
You need to use Math.Abs()
You will have to convert every number that may be negative into a positive value like so
var result = 5 - (Math.Abs(-5))
Like the title, I don't understand why that expression is always true?
Here is the detail:
// x, y, z, t is always different with each other
int x = 1;
int y = 2;
int z = 3;
int total = (int)Math.Pow(2, x) + (int)Math.Pow(2, y) + (int)Math.Pow(2, z);
int t = 4; // or any number which is not x, y, z
int result = (int)Math.Pow(2, t) & total;
result is always = 0
Can someone explain it please?
Here is some example how to apply this expression into my code :P.
I have list of day of week. I want to pick a day to go out with my friend. If today is not picked, ill not go anywhere :D
Some pre-defined value:
Day: Mon-Tue-Wed-Thu-Fri-Sat-Sun
Value: 1-2-3-4-5-6-7
I will pick Mon, Tue and Fri save value into my DB.
Instead of saving {1, 2, 5}, ill save 38 (2^1 + 2^2 + 2^5).
If today is Tue, I will check like this: 2^2 & 38 = 4. 4 is # 0 so today is the day, go out.
If today is Wed, I will check like this: 2^3 & 38 = 0. So today isn't, go to bed
To really understand what is happening here, you must first understand binary, because what you're doing with the & is a bitwise-and.
So, in our normal way of writing numbers, we use the decimal system, or base-10, system. You count from 0 to 9 and then prepend another number to indicate an "overflow": 10. In binary, or base-2, we can only count 0 or 1, before we must prepend another number. So, to count from 0 to 4 for example, we have binary: 0 = 0, 1 = 1, 2 = 10, 3 = 11, 4 = 100. Each one of these zeros or ones are bits, which are easy for a computer to calculate with since it can represent them as a transistor switching either on or off.
What you're doing here is generating numbers that are basically 1's with a lot of zeros in binary. You'll notice that if you do 10^x (Math.Pow(10, x)) you get multiples of 10 with a lot of zeros: 10, 100, 1000, 10000, etc.
2^x (Math.Pow(2, x)) does the same thing: it generates the binary numbers 1, 10, 100, 1000, 10000. In our decimal notation those binary numbers translate to 1, 2, 4, 8, 16 respectively.
Now what the & (bitwise AND) does, is return the binary code in which all the ones on the left are also one the right. So, say you have binary: 2^1 + 2^2 + 2^3 = 1 + 10 + 100 = 111.
And you do a bitwise operation with 2^4 on the left, which is 1000. So you're asking if 1000 & 0111 (you can add as many zeros to the left of any binary code, just as you could with a decimal number: 00100 is still just one hundred). This evaluates to 0000 = 0.
You noticed that when t is either x, y, or z, it returns either x, y or z respectively, effectively acting like a filter, because, well: 0010 & 0111 = 0010 (there are both ONES in the second position). A more complex example would be 0110 1100 & 1100 0101 = 0100 0100.
There; now you can calculate your computer does :-)
If you see it as binary, and as long as x,y,z are distinct numbers, the result of;
(int)Math.Pow(2, x) + (int)Math.Pow(2, y) + (int)Math.Pow(2, z)
is an integer with bit x, y and z (and only those bits) set.
(int)Math.Pow(2, t) & total
...checks if bit t is set. As long as t is distinct from x, y, z, it won't be.
It's because:
total = 14
Math(2,4) = 16
16 and 14 = 0
it's binary operation!
16 = (10000) binary
14 = (01110) binary
no common bit between them so and will return 0. If you expected othere result maybe you wanted to do or?
16 or 14 = 30
Its a binary comparison (& compares each position in the two numbers and returns 1 if both are 1):
10000 // 16 in binary
01110 // 14 in binary
00000 // 14 & 16 = 0
Use some other value there instead, and you will get a different value. Take, for example 6 and 10:
00101 // 6 in binary
01110 // 14 in binary
00100 // 6 and 14 = 8
PS: You can experiment with this type of math using the calculator on your PC by choosing View > Programmer, and switching between Bin and Dec on the left hand side.
Think of x, y, z and t as bit positions - you're doing a bitwise & which will clear any bits which aren't set in both operands, and 2t will only have the tth bit set.
So if x, y and z are all different, 2x + 2y + 2z will have bits x, y andz set, and 2t will have bit t set... so performing a bitwise AND operation on the two results will always give 0.
Now your original claim (which didn't specify that x, y and z were different) isn't quite true, because if x and y are the same (for example) the addition can effectively give you a different bit. (Addition of integer values each of which has just a single bit set is only equivalent to bitwise-OR if the operands all have different bits set.)
For example:
int x = 2;
int y = 2;
int z = 10; // Ignore this, effectively
// 2^2 + 2^2 + 2^10 == 2^3 + 2^10
int total = (int)Math.Pow(2, x) + (int)Math.Pow(2, y) + (int)Math.Pow(2, z);
int t = 3;
int result = (int)Math.Pow(2, t) & total; // result is now 8
& Does binary AND operation and hence binary ADD of 16 and 14 is 0
10000
& 01110
-------
00000
total = 14
Math(2,4) = 16
So
(10000) // 16
(01110) // 14
(00000) // 16 & 14 = 0
(int)Math.Pow(2, t) = (2^4)base 10 = (10000)base 2
total = (2^3 + 2^2 + 2^1)base 10 = (01110)base 2
& is binary AND and can be considered as multiplication between every bits
therefore
1*0 = 0
0*1 = 0
0*1 = 0
0*1 = 0
0*0 = 0
(int)Math.Pow(2, t) & total = (10000)base 2 & (01110)base 2 = (00000)base 2 = 0
Assume we have
total1 = (10001)base 2
then
(int)Math.Pow(2, t) & total1 = (10000)base 2 & (10001)base 2 = (10000)base 2 = (16)base 10
Here you are doing a binary operation by using &.
This & is equal to bitwise AND (AND gate) . AND works like this.
When 1 & 1 =1
when 1 & 0 = 0
when 0 & 1 = 0
when 0 & 0 = 0
when matching values met it will output 1 , else it will output 0.Check how and works
1001
1110
------
1000
------
so value of binary 1000 is 8
I already know when a fraction is repeating decimals. Here is the function.
public bool IsRepeatingDecimal
{
get
{
if (Numerator % Denominator == 0)
return false;
var primes = MathAlgorithms.Primes(Denominator);
foreach (int n in primes)
{
if (n != 2 && n != 5)
return true;
}
return false;
}
}
Now, I'm trying to get the repeated number. I'm checking this web site: http://en.wikipedia.org/wiki/Repeating_decimal
public decimal RepeatingDecimal()
{
if (!IsRepeatingDecimal) throw new InvalidOperationException("The fraction is not producing repeating decimals");
int digitsToTake;
switch (Denominator)
{
case 3:
case 9: digitsToTake = 1; break;
case 11: digitsToTake = 2; break;
case 13: digitsToTake = 6; break;
default: digitsToTake = Denominator - 1; break;
}
return MathExtensions.TruncateAt((decimal)Numerator / Denominator, digitsToTake);
}
But I really realized, that some numbers has a partial decimal finite and later infinite. For example: 1/28
Do you know a better way to do this? Or an Algorithm?
A very simple algorithm is this: implement long division. Record every intermediate division you do. As soon as you see a division identical to the one you've done before, you have what's being repeated.
Example: 7/13.
1. 13 goes into 7 0 times with remainder 7; bring down a 0.
2. 13 goes into 70 5 times with remainder 5; bring down a 0.
3. 13 goes into 50 3 times with remainder 11; bring down a 0.
4. 13 goes into 110 8 times with remainder 6; bring down a 0.
5. 13 goes into 60 4 times with remainder 8; bring down a 0.
6. 13 goes into 80 6 times with remainder 2; bring down a 0.
7. 13 goes into 20 1 time with remainder 7; bring down a 0.
8. We have already seen 13/70 on line 2; so lines 2-7 have the repeating part
The algorithm gives us 538461 as the repeating part. My calculator says 7/13 is 0.538461538. Looks right to me! All that remains are implementation details, or to find a better algorithm!
If you have a (positive) reduced fraction numerator / denominator, the decimal expansion of the fraction terminates if and only if denominator has no prime factor other than 2 or 5. If it has any other prime factor, the decimal expansion will be periodic. However, the cases where the denominator is divisible by at least one of 2 and 5 and where it isn't give rise to slightly different behaviour. We have three cases:
denominator = 2^a * 5^b, then the decimal expansion terminates max {a, b} digits after the decimal point.
denominator = 2^a * 5^b * m where m > 1 is not divisible by 2 or by 5, then the fractional part of the decimal expansions consists of two parts, the pre-period of length max {a, b} and the period, whose length is determined by m and independent of the numerator.
denominator > 1 is not divisible by 2 or by 5, then the decimal expansion is purely periodic, meaning the period starts immediately after the decimal point.
The treatment of cases 1. and 2. has a common part, let c = max {a, b}, then
numerator / denominator = (numerator * 2^(c-a) * 5^(c-b)) / (10^c * m)
where m = 1 for case 1. Note that one of the factors 2^(c-a) and 5^(c-b) with which we multiply the numerator is 1. Then you get the decimal expansion by expanding
(numerator * 2^(c-a) * 5^(c-b)) / m
and shifting the decimal point c places to the left. In the first case (m = 1) that part is trivial.
The treatment of cases 2. and 3. also has a common part, the calculation of a fraction
n / m
where n and m have no common prime factor (and m > 1). We can write n = q*m + r with 0 <= r < m (division with remainder, r = n % m), q is the integral part of the fraction and rather uninteresting.
Since the fraction was assumed reduced, we have r > 0, so we want to find the expansion of a fraction r / m where 0 < r < m and m is not divisible by 2 or by 5. As mentioned above, such an expansion is purely periodic, so finding the period means finding the complete expansion.
Let's go about finding the period heuristically. So let k be the length of the (shortest) period and p = d_1d1_2...d_k the period. So
r / m = 0.d_1d_2...d_kd_1d_2...d_kd_1...
= (d_1d_2...d_k)/(10^k) + (d_1d_2...d_k)/(10^(2k)) + (d_1d_2...d_k)/(10^(3k)) + ...
= p/(10^k) * (1 + 1/(10^k) + 1/(10^(2k)) + 1/(10^(3k)) + ...)
The last term is a geometric series, 1 + q + q^2 + q^3 + ... which, for |q| < 1 has the sum 1/(1-q).
In our case, 0 < q = 1/(10^k) < 1, so the sum is 1 / (1 - 1/(10^k)) = 10^k / (10^k-1). Thus we have seen that
r / m = p / (10^k-1)
Since r and m have no common factor, that means there is an s with 10^k - 1 = s*m and p = s*r. If we know k, the length of the period, we can simply find the digits of the period by calculating
p = ((10^k - 1)/m) * r
and padding with leading zeros until we have k digits. (Note: it is that simple only if k is sufficiently small or a big integer type is available. To calculate the period of for example 17/983 with standard fixed-width integer types, use long division as explained by #Patrick87.)
So it remains to find the length of the period. We can revert the reasoning above and find that if m divides 10^u - 1, then we can write
r / m = t/(10^u - 1) = t/(10^u) + t/(10^(2u)) + t/(10^(3u)) + ...
= 0.t_1t_2...t_ut_1t_2...t_ut_1...
and r/m has a period of length u. So the length of the shortest period is the minimal positive u such that m divides 10^u - 1, or, put another way, the smallest positive u such that 10^u % m == 1.
We can find it in O(m) time with
u = 0;
a = 1;
do {
++u;
a = (10*a) % m;
while(a != 1);
Now, finding the length of the period that way is not more efficient than finding the digits and length of the period together with long division, and for small enough m that is the most efficient method.
int[] long_division(int numerator, int denominator) {
if (numerator < 1 || numerator >= denominator) throw new IllegalArgumentException("Bad call");
// now we know 0 < numerator < denominator
if (denominator % 2 == 0 || denominator % 5 == 0) throw new IllegalArgumentException("Bad denominator");
// now we know we get a purely periodic expansion
int[] digits = new int[denominator];
int k = 0, n = numerator;
do {
n *= 10;
digits[k++] = n / denominator;
n = n % denominator;
}while(n != numerator);
int[] period = new int[k];
for(n = 0; n < k; ++n) {
period[n] = digits[n];
}
return period;
}
That works as long as 10*(denominator - 1) doesn't overflow, of course int could be a 32-bit or 64-bit integer as needed.
But for large denominators, that is inefficient, one can find the period length and also the period faster by considering the prime factorisation of the denominator. Regarding the period length,
If the denominator is a prime power, m = p^k, the period length of r/m is a divisor of (p-1) * p^(k-1)
If a and b are coprime and m = a * b, the period length of r/m is the least common multiple of the period lengths of 1/a and 1/b.
Taken together, the period length of r/m is a divisor of λ(m), where λ is the Carmichael function.
So to find the period length of r/m, find the prime factorisation of m and for all prime power factors p^k, find the period of 1/(p^k) - equivalently, the multiplicative order of 10 modulo p^k, which is known to be a divisor of (p-1) * p^(k-1). Since such numbers haven't many divisors, that is quickly done.
Then find the least common multiple of all these.
For the period itself (the digits), if a big integer type is available and the period isn't too long, the formula
p = (10^k - 1)/m * r
is a quick way to compute it. If the period is too long or no big integer type is available, efficiently computing the digits is messier, and off the top of my head I don't remember how exactly that is done.
One way would be to repeat the way that you do long division by hand, and keep note of the remainder at each stage. When the remainder repeats, the rest of the process must repeat as well. E.g. the digits of 1.0/7 are 0.1 remainder 3 then 0.14 remainder 2 then 0.142 remainder 6 then 0.1428 remainder 4 then 0.14285 remainder 5 then 0.142857 remainder 1 which is the 1 that starts it off again amd so you get 0.1428571 remainder 3 and it repeats again from there.
The long division algorithm is pretty good, so I have nothing to add there.
But note that your algorithm IsRepeatingDecimal may not work and is inneficient.
It will not work if your fraction is not irreductible, that is if there exists an integer larger than 1 that divides both your numerator and your denominator. For example, if you feed 7/14 then your algorithm will return true when it should return false.
To reduce your fraction, find the gcd between both numerator and denominator and divide both by this gcd.
If you assume that the fraction is irreducible, then your test
if (Numerator % Denominator == 0)
can simply be replaced with
if (Denominator == 1)
But that is still unnecessary since if Denominator is 1, then your list 'primes' is going to be empty and your algorithm will return false anyway.
Finally, calling MathAlgorithms.Primes(Denominator) is going to be expensive for large numbers and can be avoided. Indeed, all you need to do is divide your denominator by 5 (respectively 2) untill it is no longer divisible by 5 (resp. 2). If the end result is 1, then return false, otherwise return true.
I came here expecting to be able to copy & paste the code to do this, but it didn't exist. So after reading #Patrick87's answer, I went ahead and coded it up. I spent some time testing it thoroughly and giving things a nice name. I thought I would leave it here so others don't have to waste their time.
Features:
If the decimal terminates, it handles that. It calculates the period and puts that in a separate variable called period, in case you want to know the length of the reptend.
Limitations:
It will fail if the transient + reptend is longer than can be represented by a System.Decimal.
public static string FormatDecimalExpansion(RationalNumber value)
{
RationalNumber currentValue = value;
string decimalString = value.ToDecimal().ToString();
int currentIndex = decimalString.IndexOf('.');
Dictionary<RationalNumber, int> dict = new Dictionary<RationalNumber, int>();
while (!dict.ContainsKey(currentValue))
{
dict.Add(currentValue, currentIndex);
int rem = currentValue.Numerator % currentValue.Denominator;
int carry = rem * 10;
if (rem == 0) // Terminating decimal
{
return decimalString;
}
currentValue = new RationalNumber(carry, currentValue.Denominator);
currentIndex++;
}
int startIndex = dict[currentValue];
int endIndex = currentIndex;
int period = (endIndex - startIndex); // The period is the length of the reptend
if (endIndex >= decimalString.Length)
{
throw new ArgumentOutOfRangeException(nameof(value),
"The value supplied has a decimal expansion that is longer" +
$" than can be represented by value of type {nameof(System.Decimal)}.");
}
string transient = decimalString.Substring(0, startIndex);
string reptend = decimalString.Substring(startIndex, period);
return transient + $"({reptend})";
}
And for good measure, I will include my RationalNumber class.
Note: It inherits from IEquatable so that it works correctly with the dictionary:
public struct RationalNumber : IEquatable<RationalNumber>
{
public int Numerator;
public int Denominator;
public RationalNumber(int numerator, int denominator)
{
Numerator = numerator;
Denominator = denominator;
}
public decimal ToDecimal()
{
return Decimal.Divide(Numerator, Denominator);
}
public bool Equals(RationalNumber other)
{
return (Numerator == other.Numerator && Denominator == other.Denominator);
}
public override int GetHashCode()
{
return new Tuple<int, int>(Numerator, Denominator).GetHashCode();
}
public override string ToString()
{
return $"{Numerator}/{Denominator}";
}
}
Enjoy!
I am coding a program where a form opens for a certain period of time before closing. I am giving the users to specify the time in seconds. But i'd like this to be in mutliples of five. Or the number gets rounded off to the nearest multiple.
if they enter 1 - 4, then the value is automatically set to 5.
If they enter 6 - 10 then the value is automatically set to 10.
max value is 60, min is 0.
what i have, but i am not happy with this logic since it resets it to 10 seconds.
if (Convert.ToInt32(maskedTextBox1.Text) >= 60 || Convert.ToInt32(maskedTextBox1.Text) <= 0)
mySettings.ToastFormTimer = 10000;
else
mySettings.ToastFormTimer = Convert.ToInt32 (maskedTextBox1.Text) * 1000;
use the Modulus Operator
if(num % 5 == 0)
{
// the number is a multiple of 5.
}
what about this:
int x = int.Parse(maskedTextBox1.Text)/5;
int y = Math.Min(Math.Max(x,1),12)*5; // between [5,60]
// use y as the answer you need
5 * ((num - 1) / 5 + 1)
Should work if c# does integer division.
For the higher goal of rounding to the upper multiple of 5, you don't need to test whether a number is a multiple. Generally speaking, you can round-up or round-to-nearest by adding a constant, then rounding down. To round up, the constant is one less than n. Rounding an integer down to a multiple of n is simple: divide by n and multiply the result by n. Here's a case where rounding error works in your favor.
int ceil_n(int x, int n) {
return ((x+n-1) / n) * n;
}
In dynamic languages that cast the result of integer division to prevent rounding error (which doesn't include C#), you'd need to cast the quotient back to an integer.
Dividing by n can be viewed as a right-shift by 1 place in base n; similarly, multiplying by n is equivalent to a left-shift by 1. This is why the above approach works: it sets the least-significant digit of the number in base n to 0.
2410=445, 2510=505, 2610=515
((445+4 = 535) >>5 1) <<5 1 = 505 = 2510
((505+4 = 545) >>5 1) <<5 1 = 505 = 2510
((515+4 = 605) >>5 1) <<5 1 = 605 = 3010
Another way of zeroing the LSD is to subtract the remainder to set the least significant base n digit to 0, as Jeras does in his comment.
int ceil_n(int x, int n) {
x += n-1;
return x - x%n;
}