I may be using Math for evil... But, in a number written as 0.7000123
I need to get the "123" - That is, I need to extract the last 3 digits in the decimal portion of a number. The least significant digits, when the first few are what most people require.
Examples:
0.7500123 -> 123
0.5150111 -> 111
It always starts from digit 5. And yes, I'm storing secret information inside this number, in the part of the decimal that will not affect how the number is used - which is the potentially evil part. But it's still the best way around a certain problem I have.
I'm wondering whether math or string manipulation is the least dodgy way of doing this.
Performance is not an issue, at all, since I'm calling it once.
Can anyone see an easy mathematical way of doing this? eg A combination of Math functions (I've missed) in .NET?
It's a strange request to be sure. But one way to get an int value of the last 3 digits is like so:
int x = (int)((yourNumber * 10000000) % 1000);
I'm going to guess there's a better way to get the information you're looking for that's cleaner, but given what you've asked for, this should work.
First Convert Your number into the String.
string s = num.ToString();
string s1 = s.Substring(s.Length - 3, 3);
Now s1 Contains Last 3 Digits Of the Number
Using modulo will get you the last 3 digits:
var d = 0.7000123m;
d = d * 10000000 % 1000;
d will now hold the value 123.
Try this:
string value= "0.1234567";
string lastthreedigit= value.Substring(value.Length - 3);
Related
I know you can convert the Int to a string and get the digit at position x using the indexer as if it was a char array, but this conversion becomes a bit of an overhead when you're dealing with multiple large numbers.
Is there a way to retrieve a digit at position x without converting the number to a string?
EDIT:
Thank you all, I will benchmark the proposed methods and check if it is any better than converting to a string. Thread will stay unanswered for 24h in case anyone has better ideas.
EDIT 2:
After some simple tests on ulong numbers, I have concluded that converting to strings and extracting the digit can be up to 50% slower compared to the methods provided below, see approved answer.
You could do something like this:
int ith_digit(int n, int i) {
return (int) (n / pow(10, i)) % 10;
}
We can get the ith digit by reducing the number down to a point where that digit we want becomes in the one's place, example:
Let's say you wanted the third digit in 12345, then by reducing it to 123 (by dividing it by 10 i number of times) we can then take the remainder of that number divided by ten to get the last digit, which is the digit we wanted.
There have been many questions but i can't seem to find the why in the answers. It's usually: no, replace this with this or this should work.
My task is to create a program that asks the user to input a 3 digit positive integer (decimal) that converts it to octal.
For example, on paper: To convert the number 112 to octal. (8 is the base number for octal.)
These are the steps you would take:
112 / 8 = 14 remainder = 0
14 / 8 = 1 remainder = 6
1 / 8 = 0 remainder = 1
Remainder from bottom to up is the octal number that represents 112 in decimal.
So the octal number for 112 is 160.
I found the following program on the internet but i don't understand it fully.
The comments in the program are mine. Could anyone explain it to me please?
//declaration and initialization of variables but why is there an array?
int decimalNumber, quotient, i = 1, j;
int[] octalNumber = new int[100];
//input
Console.WriteLine("Enter a Decimal Number :");
decimalNumber = int.Parse(Console.ReadLine());
quotient = decimalNumber;
//as long as quotient is not equal to 0, statement will run
while (quotient != 0)
{
//this is how the remainder is calculated but it is then put in an array + 1, i don't understand this.
octalNumber[i++] = quotient % 8;
//divide the number given by the user with the octal base number
quotient = quotient / 8;
}
Console.Write("Equivalent Octal Number is ");
//i don't understand the code below here aswell.
for (j = i - 1; j > 0; j--)
Console.Write(octalNumber[j]);
Console.Read();
Any help is truly appreciated.
The first thing to understand is: this is a terrible way to solve this problem. The code is full of odd choices; it looks like someone took a bad C solution of this problem and translated it to C# without applying careful thought or using good practices. If you are trying to learn how to understand crappy code you find on the internet, this is a great example. If you are trying to learn how to design good code, this is a great example of what not to do.
//declaration and initialization of variables but why is there an array?
There's an array because we wish to store all the octal digits, and an array is a convenient mechanism for storing a number of data of the same type.
But we could ask some more pertinent questions here:
Why of size 100? It's not wrong, but that's enormously larger than necessary. What thought process led to 100 being chosen? Why wasn't that thought process documented anywhere?
Why an array of int? We're outputting text, which is a sequence of chars. It would seem more natural to have a bunch of chars.
Why an array? Since we are building a first-in-last-out data structure, a stack seems more appropriate. Or why not simply accumulate a string? That's inefficient if the string is large, but an octal string from a 32 bit integer is never large!
Why does the program produce output to the console? Surely a better factored program would have a method that takes an int and returns an octal string, which can then be printed.
Why do some of the variables have descriptive names and some have undescriptive names? Is the author of the code deliberately trying to confuse the reader? Or did they simply not think about it very carefully?
Why does i - apparently the current index into the array -- start at one?! This is simply bizarre. Arrays start at zero in C#.
What happens if you type in a negative number? Try it!
What happens if you type in zero?
We then go on to:
decimalNumber = int.Parse(Console.ReadLine());
This code presumes that the typed-in text is a legal integer, which is not guaranteed. So this program can crash. TryParse should be used, and the failure mode should be handled.
// this is how the remainder is calculated but it is
// then put in an array + 1, i don't understand this.
octalNumber[i++] = quotient % 8;
The author of the code thinks they are being clever. This is too much cleverness. Rewrite the code in your head to how it should have been implemented in the first place. First, rename i to currentIndex. Next, produce one side effect per statement, not two:
while (quotient != 0)
{
octalNumber[currentIndex] = quotient % 8;
currentIndex += 1;
quotient = quotient / 8;
}
Now it should be clear what is going on.
// I don't understand the code below here as well.
for (j = i - 1; j > 0; j--)
Console.Write(octalNumber[j]);
Do a little example. Suppose the number is 14, which is 16 in octal. First time through the loop we put 6 in slot 1. Next time through, we put 1 in slot 2. So the array is {0, 6, 1, 0, 0, 0, 0 ... } and i is 3. We wish to output 16. So we loop j from i-1 to 1, and print out 1 then 6.
So, exercise for you: write this program again, this time using the conventions of a well-designed C# program. Put your attempt on the code review site and people will be happy to give you tips on how to improve it.
This is already built into .NET, Convert.ToString already does this.
In your code, just after you have decimalNumber = int.Parse(...) you can do this:
Console.WriteLine(Convert.ToString(decimalNumber, 8));
Console.Read();
and then remove the rest of the code.
Now, if you're not asking how to do octal conversion in .NET but actually how that code works, here's how it works:
This loop does the heavy lifting:
1 while (quotient != 0)
{
//this is how the remainder is calculated but it is then put in an array + 1, i don't understand this.
2 octalNumber[i++] = quotient % 8;
//divide the number given by the user with the octal base number
3 quotient = quotient / 8;
}
I added some numbers to the lines to make it easier writing a description.
Basically, the loop does this (lines above correspond to points below).
As long as we have a number to convert (ie. we're still not done), loop.
Figure out the least significant digit, this is the remainder after dividing by 8, which is handled by the remainder operator, %, store this digit into the array in the next position.
Divide by 8 to get rid of that least significant digit and move all the other digits one up
Then loop back.
However, since we essentially found all the digits from the rightmost side towards the left, the loop at the end writes them back out in their opposite order.
As an exercise to the reader, try to figure out how the code in the question behaves if you:
Input a negative number
Input 0
(hint, it doesn't behave correctly but Convert.ToString does)
An array is used because they are calculating each digit every interation of the while loop. (e.g.) {0, 6, 1}
The last part of the program is printing each digit out, starting with the last item in the array and moving to the first. in this case it would print out:
160
Basically I'm trying to perform number formatting in the exact same way as the Windows calculator does. Hence, my requirements are:
Limit the number of displayed digits to a maximum (e.g. 16). I was able to accomplish that using number.ToString("G16").
Add digit grouping to the number. I was able to accomplish that using: number.ToString(String.Format("#,0.{0};-#,0.{0}", New String("#"c, 15)))
Any ideas on how to combine these together to get the same behavior as Windows calculator?
Some examples with the desired output:
I added an answer below which I would be using if the desired output can't be achieved using one string formatting. Feel free to suggest any optimizations/changes to that answer if you believe no direct way to achieve this (which is my original requirement)
Sorry if I caused some kind of confusion to anyone. I just thought that there might be a simple one string formatting to achieve this and I was -and still am- curious to find out if that's true.
After a lot of search on this issue. You cannot perform this with a single format because you are asking about an IF .. ELSE LOGIC not for a one-way formatting (performing two formatting on a number)
IF d.ToString("G16") contains scientific notation
... do something
ELSE
... group digits
So you have to use an IF to achieve this
Str = If( num.ToString("G15").Contains("e"), num.ToString("G15"), num.ToString(String.Format("#,0.{0};-#,0.{0}", New String("#"c, 15))))
Update1
Based on your update use the following
Public Function FormatDouble(ByVal dbl As Double, ByVal len As Integer) As String
Return Double.Parse(dbl.ToString("G" & len)).ToString("#,#.#".PadRight(len, "#"), System.Globalization.CultureInfo.InvariantCulture)
End Function
dbl.ToString("G" &len) is formatting dbl to a fixed length = len
Double.parse is converting the result again to double with the new length. Note: if th result contains e it will be removed after parse
ToString("#,#.#".PadRight(len, "#"), System.Globalization.CultureInfo.InvariantCulture) is adding Group digits to the resulted double
Note
When providing length ("G15") it will round the number to it. It may reduce length from decimal part but it doesn't from the integers it will round the number to the specified length. I.e. 1734.Tostring("G1") will returns 2000 but not 2 / 1734.Tostring("G2") will returns 1700 but not 17
If you want to reduce numbers you have to use String Functions like Substring And Left after the Tostring("G1")
Hope it helps
I don't know an easy way to do that in the way you are looking for.
But being a curious sort of fellow I did wonder how it could be achieved using only string methods.
To be clear, I'm not advocating this approach as a good solution - it's rather hard to understand in one line, but hey, an interesting exercise for me.
If you felt like doing it in one horrendous line (c#):
var num1 = 123123123.456456456; // result: 123,123,123.4564565
//var num1 = 123123123456456456.78; // result: 1.231231234564565E+17
//var num1 = 123123123456; // result: 1,231,231,234,564,564
//var num1 = 1231231; // result: 1,231,231
Console.WriteLine(long.Parse((num1.ToString("G16") + ".").Substring(0, (num1.ToString("G16") + ".").IndexOf('.'))).ToString("N0") + (num1.ToString("G16") + ".").Substring((num1.ToString("G16") + ".").IndexOf('.'), (num1.ToString("G16") + ".").LastIndexOf('.')- (num1.ToString("G16") + ".").IndexOf('.')));
Otherwise broken up a little; it's a little clearer what approach I'm taking:
var num1 = 123123123.456456456;
var num1a = num1.ToString("G16") + ".";
Console.WriteLine(long.Parse(num1a.Substring(0, num1a.IndexOf('.'))).ToString("N0") + num1a.Substring(num1a.IndexOf('.'), num1a.LastIndexOf('.')- num1a.IndexOf('.')));
I'm adding a decimal point to the end of the string so that there is at least one decimal point in the number (string). Then grab the text to the left of the first decimal point and concatenate it with any text from the first and to the left of the last decimal point.
If there was no decimal point in the original string then these two points are the same - the substring 0 characters long - removing the added decimal point.
This is an answer I would be using if this can't be done using one string formatting:
Private Function RoundAndGroup(num As Decimal) As String
' This will round the input to limit the number of digit to 16.
Dim rounded As String = num.ToString("G16")
' Take only the whole part of the number to group and then combine with the rounded part.
Dim whole As String = rounded.Split(".")(0)
' Group the whole part (if any) and combine with the rounded part (also if any).
Dim grouped As String = Long.Parse(whole).ToString("N0") & ' Thanks to KScandrett's comment
rounded.Substring(whole.Length)
Return grouped
End Function
This will -AFAICT- produce my desired output (the same output of Windows calculator).
I just thought that there might be a simple one string formatting to achieve this and I was -and still am- curious to find out if that's true.
You can use String.format to apply multiple formats. Read about Composite Formatting here :
String.Format("{0:N0}", Clng(number.ToString("G16")))
Tested in vb.net
You can drop the zeros or use your formatting, but the original question was about applying multiple formats.
You might need to convert the number to long while formatting, test it out at your end.
For part 2, you can just use N0 to add the commas for thousands places - Standard Numeric Format Strings
static formatDecimal(decimal decimalVar, int size)
{
return decimalVar.ToString("#.##").PadLeft(size, '0');
}
I'm working on a simple game and I have the requirement of taking a word or phrase such as "hello world" and converting it to a series of numbers.
The criteria is:
Numbers need to be distinct
Need ability to configure maximum sequence of numbers. IE 10 numbers total.
Need ability to configure max range for each number in sequence.
Must be deterministic, that is we should get the same sequence everytime for the same input phrase.
I've tried breaking down the problem like so:
Convert characters to ASCII number code: "hello world" = 104 101 108 108 111 32 119 111 114 108 100
Remove everyother number until we satisfy total numbers (10 in this case)
Foreach number if number > max number then divide by 2 until number <= max number
If any numbers are duplicated increase or decrease the first occurence until satisfied. (This could cause a problem as you could create a duplicate by solving another duplicate)
Is there a better way of doing this or am I on the right track? As stated above I think I may run into issues with removing distinction.
If you want to limit the size of the output series - then this is impossible.
Proof:
Assume your output is a series of size k, each of range r <= M for some predefined M, then there are at most k*M possible outputs.
However, there are infinite number of inputs, and specifically there are k*M+1 different inputs.
From pigeonhole principle (where the inputs are the pigeons and the outputs are the pigeonholes) - there are 2 pigeons (inputs) in one pigeonhole (output) - so the requirement cannot be achieved.
Original answer, provides workaround without limiting the size of the output series:
You can use prime numbers, let p1,p2,... be the series of prime numbers.
Then, convert the string into series of numbers using number[i] = ascii(char[i]) * p_i
The range of each character is obviously then [0,255 * p_i]
Since for each i,j such that i != j -> p_i * x != p_j * y (for each x,y) - you get uniqueness. However, this is mainly nice theoretically as the generated numbers might grow quickly, and for practical implementation you are going to need some big number library such as java's BigInteger (cannot recall the C# equivalent)
Another possible solution (with the same relaxation of no series limitation) is:
number[i] = ascii(char[i]) + 256*(i-1)
In here the range for number[i] is [256*(i-1),256*i), and elements are still distinct.
Mathematically, it is theoretically possible to do what you want, but you won't be able to do it in C#:
If your outputs are required to be distinct, then you cannot lose any information after encoding the string using ASCII values. This means that if you limit your output size to n numbers then the numbers will have to include all information from the encoding.
So for your example
"Hello World" -> 104 101 108 108 111 32 119 111 114 108 100
you would have to preserve the meaning of each of those numbers. The simplest way to do this would just 0 pad your numbers to three digits and concatenate them together into one large number...making your result 104101108111032119111114108100 for max numbers = 1.
(You can see where the issue becomes, for arbitrary length input you need very large numbers.) So certainly it is possible to encode any arbitrary length string input to n numbers, but the numbers will become exceedingly large.
If by "numbers" you meant digits, then no you cannot have distinct outputs, as #amit explained in his example with the pidgeonhole principle.
Let's eliminate your criteria as easily as possible.
For distinct, deterministic, just use a hash code. (Hash actually isn't guaranteed to be distinct, but is highly likely to be):
string s = "hello world";
uint hash = Convert.ToUInt32(s.GetHashCode());
Note that I converted the signed int returned from GetHashCode to unsigned, to avoid the chance of having a '-' appear.
Then, for your max range per number, just convert the base.
That leaves you with the maximum sequence criteria. Without understanding your requirements better, all I can propose is truncate if necessary:
hash.toString().Substring(0, size)
Truncating leaves a chance that you'll no longer be distinct, but that must be built in as acceptable to your requirements? As amit explains in another answer, you can't have infinite input and non-infinite output.
Ok, so in one comment you've said that this is just to pick lottery numbers. In that case, you could do something like this:
public static List<int> GenNumbers(String input, int count, int maxNum)
{
List<int> ret = new List<int>();
Random r = new Random(input.GetHashCode());
for (int i = 0; i < count; ++i)
{
int next = r.Next(maxNum - i);
foreach (int picked in ret.OrderBy(x => x))
{
if (picked <= next)
++next;
else
break;
}
ret.Add(next);
}
return ret;
}
The idea is to seed a random number generator with the hash code of the String. The rest of that is just picking numbers without replacement. I'm sure it could be written more efficiently - an alternative is to generate all maxNum numbers and shuffle the first count. Warning, untested.
I know newer versions of the .Net runtime use a random String hash code algorithm (so results will differ between runs), but I believe this is opt-in. Writing your own hash algorithm is an option.
This question already has answers here:
Mapping two integers to one, in a unique and deterministic way
(19 answers)
Closed 7 years ago.
I need to find a way, such that user has to input 2 numbers (int) and for every different value a single output (int preferably!) is returned.
Say user enters 6, 8 it returns k when user enter anything else like 6,7 or 9,8 or any other input m, n except for 6, 8 (even if only one input is changed) a completely different output is produced. But the thing is, it should be unique for only that m, n so I cant use something like m*n because 6 X 4 = 24 but also, 12 X 2 = 24 so the output is not unique, so I need to find a way where for every different input, there is a totally different output that is not repeated for any other value.
EDIT: In response to Nicolas: the input range can be anything but will be less then 1000 (but more then 1 of course!)
EDIT 2: In response to Rawling, I can use long (Int64) but not preferably use float or doulbe, becuase this output will be used in a for loop, and float and double are terrible for for loop, you can check it here
Since your two numbers are less than 1000, you can do k = (1000 * x1) + x2 to get a unique answer. The maximum value would be 999999, which is well within the range of a 32-bit int.
You can always return a long: from two integers a and b, return 2^|INT_SIZE|*a + b
It is easy to see from pigeonhole principle, that given two ints, one cannot return a unique int for every different input. Explanation: If you have 2 numbers, each containing n bits, then there are 2^n possibilities for each number, and thus there are (2^n)^2 possible pairs, so from piegeonhole principle - you need at least lg_2((2^n)^2) = 2n bits to represent them,
EDIT: Your edit mentions the range of your numbers is [1,1000] - thus the same idea can be applied: 1000*a + b will generate a unique int for each pairs.
Note that for the same reasons, the range of the resulting integer must be [1,1000000] - or you will get clashes.
Because I don't have 50 posts to comment, I must say, there are functions
called Pairing Functions.
Pairing functions such as Cantor's Pairing Function(Shown on the previous link) and Szudzik's Pairing Function which allows the inputs to be infinite and still be able to provide an unique and deterministic output.
Here is another similar question on stackoverflow. (Great, I need 10 reputation to post more than two links..)
(http://) stackoverflow.com/questions/919612/mapping-two-integers-to-one-in-a-unique-and-deterministic-way
EDIT: I'm late.
If you didn't have a hard upper bound, you could do the following:
int Unique (int x, int y)
{
int n = x + y;
int t = (n%2==0) ? ((n/2) * (n+1)) : (n * ((n+1)/2));
return t + x;
}
Mathematically speaking, this will return a unique non negative integer for each (non-negative) pair of integers with no upper bound.
Programatically speaking, it will run into overflow problems, which could be overcome by using long instead of int for everything except the input variables.
The canonical mathematical solution is to use prime powers. As every number can be decomposed uniquely into its prime factors, returning 2^n * 3^m will give you different results for every n and m.
This can be extended to 2^n * 3^m * 5^a * 7^b *11^c and so on; you only need to check that you do not run out of 32-bit integers. If there is a risk of overflowing, you can take the remainder after dividing by a prime larger than your input range, and you will still have uniqueness.