Get min and max integer value containing X number of digits - c#

What would be the best way to generate the lowest and highest integer values which contain x number of digits?
For example:
x = 1: Min = 0, Max = 9
x = 2: Min = 10, Max = 99
x = 3: Min = 100, Max = 999
x = 4: Min = 1000, Max = 9999
I feel like this should be a really easy thing to accomplish but I'm struggling to get my head around the math behind it.
Here's what I've got so far for generating the max value (based on this answer):
public static int MaxIntWithXDigits(this int x)
{
if (x == 0) throw new ArgumentException(nameof(x), "An integer cannot contain zero digits.");
try
{
return Convert.ToInt32(Math.Pow(10, x) -1);
}
catch
{
throw new InvalidOperationException($"A number with {x} digits cannot be represented as an integer.");
}
}
If anyone can help with generating the min value or suggest improvements on the code above I'd appreciate it.
Edit
I'm almost there - this seems to work for everything except when x = 1 (and min value expected as 0)
public static int MinIntWithXDigits(this int x)
{
if (x == 0) throw new ArgumentException(nameof(x), "An integer cannot contain zero digits.");
x -= 1;
try
{
return Convert.ToInt32(Math.Pow(10, x));
}
catch
{
throw new InvalidOperationException($"A number with {x} digits cannot be represented as an integer.");
}
}

Fox any x>1, the min value would be 10x-1. E.g.:
If x = 2, min=102-1 = 101 = 10
If x = 3, min=103-1 = 102 = 100
If x = 4, min=104-1 = 103 = 1000
For x=1, since it's the only value that is not a one followed by a series of zeroes, you'll need special treatment.
public static int MinIntWithXDigits(this int x)
{
if (x == 0)
{
throw new ArgumentException(nameof(x), "An integer cannot contain zero digits.");
}
if (x == 1) {
return 0;
}
try
{
return Convert.ToInt32(Math.Pow(10, x - 1));
}
catch
{
throw new InvalidOperationException($"A number with {x} digits cannot be represented as an integer.");
}
}
Side note:
If the result were restricted to positive integers instead of non-negative integers, the smallest integer with one digit would be 1, and the general formula would have applied for this case too.

You can try something like this:
// let's return min and max in one go as a value tuple
public static (int min, int max) MaxIntWithXDigits(this int x) {
if (x <= 0 || x > 9)
throw new ArgumentOutOfRangeException(nameof(x));
int min = (int)Math.Pow(10, x - 1);
return (min == 1 ? 0 : min, min * 10 - 1);
}
Demo:
var result = Enumerable
.Range(1, 9)
.Select(x => $"{x} : {MaxIntWithXDigits(x).min} .. {MaxIntWithXDigits(x).max}");
Console.Write(string.Join(Environment.NewLine, result));
Outcome:
1 : 0 .. 9
2 : 10 .. 99
3 : 100 .. 999
4 : 1000 .. 9999
5 : 10000 .. 99999
6 : 100000 .. 999999
7 : 1000000 .. 9999999
8 : 10000000 .. 99999999
9 : 100000000 .. 999999999

Related

Pairs of amicable numbers

I have a task to find pairs of amicable numbers and I've already solved it. My solution is not efficient, so please help me to make my algorithm faster.
Amicable numbers are two different numbers so related that the sum of the proper divisors of each is equal to the other number. The smallest pair of amicable numbers is (220, 284). They are amicable because the proper divisors of 220 are 1, 2, 4, 5, 10, 11, 20, 22, 44, 55 and 110, of which the sum is 284; and the proper divisors of 284 are 1, 2, 4, 71 and 142, of which the sum is 220.
Task: two long numbers and find the first amicable numbers between them. Let s(n) be the sum of the proper divisors of n:
For example:
s(10) = 1 + 2 + 5 = 8
s(11) = 1
s(12) = 1 + 2 + 3 + 4 + 6 = 16
If s(firstlong) == s(secondLong) they are amicable numbers
My code:
public static IEnumerable<long> Ranger(long length) {
for (long i = 1; i <= length; i++) {
yield return i;
}
}
public static IEnumerable<long> GetDivisors(long num) {
return from a in Ranger(num/2)
where num % a == 0
select a;
}
public static string FindAmicable(long start, long limit) {
long numberN = 0;
long numberM = 0;
for (long n = start; n <= limit; n++) {
long sumN = GetDivisors(n).Sum();
long m = sumN;
long sumM = GetDivisors(m).Sum();
if (n == sumM ) {
numberN = n;
numberM = m;
break;
}
}
return $"First amicable numbers: {numberN} and {numberM}";
}
I generally don't write C#, so rather than stumble through some incoherent C# spaghetti, I'll describe an improvement in C#-madeup-psuedo-code.
The problem seems to be in your GetDivisors function. This is linear O(n) time with respect to each divisor n, when it could be O(sqrt(n)). The trick is to only divide up to the square root, and infer the rest of the factors from that.
GetDivisors(num) {
// same as before, but up to sqrt(num), plus a bit for floating point error
yield return a in Ranger((long)sqrt(num + 0.5)) where num % a == 0
if ((long)sqrt(num + 0.5) ** 2 == num) { // perfect square, exists
num -= 1 // don't count it twice
}
// repeat, but return the "other half"- num / a instead of a
yield return num/a in Ranger((long)sqrt(num + 0.5)) where num % a == 0
}
This will reduce your complexity of that portion from O(n) to O(sqrt(n)), which should provide a noticeable speedup.
There is a simple formula giving the sum of divisors of a number knowing its prime decomposition:
let x = p1^a1 * ... * pn^an, where pi is a prime for all i
sum of divisors = (1+p1+...+p1^a1) * ... (1+pn+...+pn^an)
= (1-p1^(a1+1))/(1-p1) * ... ((1-pn^(an+1))/(1-pn)
In order to do a prime decomposition you must compute all prime numbers up to the square root of the maximal value in your search range. This is easily done using the sieve of Erathostenes.

Get divisible numbers in a range without certain operators (+, -, /, *, %, += %=, etc)

find numbers in an input range that are evenly divisible by 3. Only =, ++, -- operators can be used.
I've tried to get the remainder using shift operators and other loops but I always require a -= or something similar.
Console.Clear();
int n,
d,
count = 1;
// get the ending number
n = getNumber();
// get the divisor
d = 3;// getDivisor();
Console.WriteLine();
Console.WriteLine(String.Format("Below are all the numbers that are evenly divisible by {0} from 1 up to {1}", d, n));
Console.WriteLine();
// loop through
while (count <= n)
{
// if no remainder then write number
if(count % d == 0)
Console.Write(string.Format("{0} ", count));
count++;
}
Console.WriteLine();
Console.WriteLine();
Console.Write("Press any key to try again. Press escape to cancel");
Expected results:
Enter the ending number: 15
Below are all the numbers that are evenly divisible by 3 from 1 up to 15
3, 6, 9, 12, 15
If the == operator is permitted for the assignment, you can have something like
int remainder = 0; // assumes we always count up from 1 to n, we will increment before test
Inside the loop replace the existing if with
remainder++;
if (remainder == 3) {
Console.Write(string.Format("{0} ", count));
remainder = 0;
}
[EDIT: Typo in code corrected]
Think about the underlying maths:
2 x 3 = 3 + 3
3 x 3 = 3 + 3 + 3
4 * 3 = 3 + 3 + 3 + 3
...and so on.
Also, to be evenly divisible by 3 means that the number multiplying 3 must be even.. So...
public bool EvenlyDivisibleBy3(int aNumber)
{
int even = 2;
int currentMultiple = 0;
while (currentMultiple < aNumber)
{
int xTimes = 0;
for (int x = 1; x <= even; x++)
{
((xTimes++)++)++; // add three to xTimes
}
currentMultiple = xTimes;
(even++)++: // next even number
}
return currentMultiple == aNumber;
}

Algorithm to get which values make sum of a given number from array

I don't know to search or google it so I ask it here.
I have an array of integers with fixed size and exactly with this logic.
sample [1,2,4,8,16,32]
Now I am given a number for example 26. And I shall find the numbers whose sum will make this number, in this case is [2,8,16]
for a number of 20 it will be [4,16]
for 40 it is [8,32]
and for 63 it is all of these numbers [1,2,4,8,16,32]
What is the proper algorithm for that?
I know strictly that there is always this continuation that the number is double of the previous value.
as well as only the numbers from the given array will sum up to the given number and each number will be used only for once or none
If it will be in C# method that takes array of ints and an int value and returns the array of ints that contains the ints that sum up this number from the given array will be preferred.
Thank you
As you can see, the number are base-2, which means you can easily use shift.
You could try this:
private IEnumerable<int> FindBits(int value)
{
// check for bits.
for (int i = 0; i < 32; i++)
{
// shift 1 by i
var bitVal = 1 << i; // you could use (int)Math.Pow(2, i); instead
// check if the value contains that bit.
if ((value & bitVal) == bitVal)
// yep, it did.
yield return bitVal;
}
}
This method will check what bits are set and return them as an ienumerable. (which can be converted to an array of list)
Usage:
// find the bits.
var res = FindBits(40).ToArray();
// format it using the string.join
var str = $"[{string.Join(",", res)}]";
// present the results
Console.WriteLine(str);
Results in [8,32]
Extra info:
counter
00000001 = 1 = 1 << 0
00000010 = 2 = 1 << 1
00000100 = 4 = 1 << 2
00001000 = 8 = 1 << 3
00010000 = 16 = 1 << 4
00100000 = 32 = 1 << 5
01000000 = 64 = 1 << 6
10000000 = 128 = 1 << 7
Instead of writing all combinations you make a for loop which does the counter.
Some extra non-sense:
If you like lambda's, you could replace the FindBits with this:
private Func<int, IEnumerable<int>> FindBits = (int value) => Enumerable
.Range(0, 31)
.Select(i => 2 << i).Where(i => (value & i) == i);
But it's better to keep it simpel/readable.
First you should notice that
( 1 2 4 8 16 ... ) = (2^0 2^1 2^2 2^3 2^4 ... )
And that this is the same as finding a binary encoding for a decimal number. What you are looking for is an algorithm to transform a decimal or base 10 number to a binary or base 2 number.
The algorithm is pretty simple:
public List<int> dec_to_bin(int num)
{
List<int> return_list = new List<int>();
int index = 0;
int remainder = num;
int bit = 0;
while (remainder > 0)
{
bit = remainder % 2;
if (bit == 1 )
{
return_list.Add((int)Math.Pow(2, index));
}
remainder = remainder / 2;
index = index + 1;
}
return return_list;
}
There is a better way however that just uses the underlying encoding of the number which is already binary.
public List<int> dec_to_bin(int num)
{
List<int> return_list = new List<int>();
int value = 1;
while( value < num )
{
if( (value & num) == value )
{
return_list.Add(value);
}
value = value * 2;
}
return return_list;
}
Another way to state your requirement is "What are the unique powers of 2 that sum to a given integer?" Since computers work with powers of 2 natively, there are built-in goodies in most languages to do this very succinctly.
As a bonus, you can use existing .Net types and methods to eliminate the need to write your own loops.
Here's one approach:
IEnumerable<int> GetCompositePowersOf2(int input) =>
//convert to enumerable of bools, one for each bit in the
//input value (true=1, false=0)
new BitArray(new[] { input }).Cast<bool>()
// get power of 2 corresponding to the position in the enumerable
// for each true value, gets 0 for false values.
.Select((isOne, pos) => isOne ? (1 << pos) : 0)
//filter out the 0 values
.Where(pow => pow > 0);
I don't quite get the " takes array of ints " part, since this creation of sums only works with numbers that are the power of 2.
private int[] count (int num)
{
int factor = 0;
List<int> facts = new List<int>();
while (num > 0)
{
int counter = 0;
int div = num;
int remainder = 0;
while (remainder == 0)
{
remainder = div % 2;
div = div / 2;
counter++;
}
factor = 1;
for (int i = 1; i < counter; i++)
factor *= 2;
num = num - factor;
facts.Add(factor);
}
return (facts.ToArray());
}

Divide number into defined stacks

So basically I want to split a number, for example: 862 in C#
into stacks of 100 (or below with remainder), so it would result in:
100, 100, 100, 100, 100, 100, 100 , 100, 62
I know this is probably easily done, but I've searched and couldn't quite found a solution. I don't quite know what to search as well so that could possibly be the issue.
Cheers
This is simple division to get the number of 100 stacks and modulo to get the remainder.
int number = 862;
int stackSize = 100;
var results = Enumerable.Repeat(stackSize, number / stackSize);
if (number % stackSize > 0)
results = results.Concat(Enumerable.Repeat(number % stackSize, 1));
Console.WriteLine(string.Join(", ", results));
outputs
100, 100, 100, 100, 100, 100, 100, 100, 62
Or as a one liner (credit to spendor)
var results = Enumerable.Repeat(stackSize, number / stackSize)
.Concat(Enumerable.Repeat(number % stackSize, 1))
.Where(‌​x => x > 0);
This should do the trick:
static int[] DivideIntoStacks(int number, int stacksize)
{
int num = number;
List<int> stacks = new List<int>();
while (num > 0)
{
if (num - stacksize >= 0)
{
stacks.Add(stacksize);
num -= stacksize;
}
else
{
stacks.Add(num);
break;
}
}
return stacks.ToArray();
}
For your example, call the function with: DivideIntoStacks(862, 100)
This supplies you with an int[] with the desired values.
while the number is greater than stackSize, add a stackSize to the stack, and subtract that from the number. Once the number is less than stackSize, if there's a remainder, add that to the stack:
static void Main(string[] args)
{
int stackSize = 100;
int num = 862;
var stacks = new List<int>();
while (num > stackSize)
{
stacks.Add(stackSize);
num -= stackSize;
}
if (num > 0)
{
stacks.Add(num);
}
}
I'm sure there's some spiffy LINQ one-liner to do this as well.
int number = 862;
int d = number / 100;
if(d == 0)
{
return (d).ToString();
}
int r = number % 100;
string str = string.Join(",", Enumerable.Repeat("100", d));
if(number % 100 > 0)
str = str + ", " + r;
return str;
Example works for non whole numbers. Just check if value is less then 100 or d == 0(You can check by any of these), so return zero.
get the total number of hundreds in number and build a comma separated string.
At the end if value has some remainder with 100 append to the string with comma.

C#: A Bounding Max and Min on Array[]

Suppose I have a List. I'd like to be able to calculate semi-equi-distant max and min bounding points. I don't want to simply get the Max() and Min() its slightly more complicated.
To start, I'd like to specify a point in the list in which the list can be divided. To make it easy for now, suppose that point is 0. I'd then like to specify the number of divisions. Example:
List<int> Array = {-9,-8,-7,-2,-1,0,1,6,9,12};
int Divisions = 4;
int CutOff = 0;
So using these parameters I'd like to walk out to the extremes starting from 0 until there are 4 divisions. In this case the DivisionSize should be 6.
So the algorithm would start at 0 and walk to -6 for 1 Division then walk to -12 for the 2nd division. -12 would then become the bounding Min for the purposes of this algorithm.
The Max would then be calculated by starting at 0 and walking to 6, then 12. The bounding Max would then be 12. Its okay if the Calculate Max and Min are the actual Max and Min of the list, this is just an unlikely case.
I'm basically have some issues calculating the DivisionSize. I started with (Abs(Max)+Abs(Min))/Divisions but I can't seem to get the edge case where the Calculated size of the each division needs to be expanded to actually encompass the original Min and Max. Can somebody provided some guidance?
Edit: I don't necessarily want the BoundedMax and BoundedMin to be symmetrical about the cutoff. I want to add slack to either side of the cutoff until the BoundedMin and BoundedMax are >= and <= the range of the List.
Since your divisions are going to be "semi-equidistant" from the cutoff, your algorithm should only focus on half the divisions (one side from the cutoff). The next step would be to determine which of the "sides" of the cutoff is larger.
Next, we divide the larger side by half the division, and get the Ceiling of the value (round to next higher integer). This will give us the size of each division of the larger side which would encompass all the values on both sides of the cutoff.
The following algorithm would give you the DivisionSize of 6 when applied to the example you provided:
int NewMax = Abs(Max - CutOff);
int NewMin = Abs(Min - CutOff);
int DivisionSize = (int)Math.Ceiling(NewMax > NewMin ? NewMax/(Divisions/2) : NewMin/(Divisions/2));
L = abs(min(A)-cut)
R = abs(max(A)-cut)
size = max(L,R) # ate least two divisions
while divisions >= (1+(L-1)/size + 1+(R-1)/size)
size = size-1
size = size+1
Lets try it out:
L = 9
R = 12
size = 12
d = 1 + (9-1)/12 + 1 + (12-1)/12 = 1 + 1 = 2
size = 11
d = 1 + (9-1)/11 + 1 + (12-1)/11 = 1 + 2 = 3
size = 10
d = 1 + (9-1)/10 + 1 + (12-1)/10 = 1 + 2 = 3
size = 9
d = 1 + (9-1)/9 + 1 + (12-1) / 9 = 1 + 2 = 3
size = 8
d = 1 + (9-1)/8 + 1 + (12-1) / 8 = 2 + 2 = 4
size = 7
d = 1 + (9-1)/7 + 1 + (12-1) / 7 = 2 + 2 = 4
size = 6
d = 1 + (9-1)/6 + 1 + (12-1) / 6 = 2 + 2 = 4
size = 5
d = 1 + (9-1)/5 + 1 + (12-1) / 5 = 2 + 3 = 5
--> size = 6
Note that the integer divisions must be floored (not rounded).
For optimization, you can use a binary search between 1 and R for the size.
I think the key is to determine how many of your divisions you want either side of the CutOff point, by taking the ratio of each side's length to the total length.
In your example, the sides are 9 and 12, giving (approx) 1.7 and 2.2 divisions either side. The actual numbers must be integers, so try (1,3) and (2,2). 1 division on the left means the size must be 9, 2 divisions on either side allow you to use division size 6.
Wrote some C# to illustrate this. Not particularly elegant, but it seems to work.
public class RangeDivider
{
public int Min;
public int CutOff;
public int Max;
public int NumDivisions;
public RangeDivider(int min, int cutOff, int max, int numDivisions)
{
Min = min;
CutOff = cutOff;
Max = max;
NumDivisions = numDivisions;
System.Diagnostics.Debug.Assert(Min < CutOff && CutOff < Max && numDivisions >= 2);
}
public int LeftSize { get { return CutOff - Min; } }
public int RightSize { get { return Max - CutOff; } }
public int WholeSize { get { return Max - Min; } }
private static int divCeil(int dividend, int divisor) { return 1 + (dividend - 1)/divisor; }
private int ReturnSize(int leftDivisions)
{
int rightDivisions = NumDivisions - leftDivisions;
if (leftDivisions > 0 && rightDivisions > 0)
{
return Math.Max(divCeil(LeftSize, leftDivisions), divCeil(RightSize, rightDivisions));
}
else
{ //Must have at least 1 division each side of cutoff
return int.MaxValue;
}
}
public int GetSize()
{
var leftDivisions = NumDivisions * LeftSize / WholeSize;
var size = Math.Min(ReturnSize(leftDivisions), ReturnSize(leftDivisions + 1));
Console.WriteLine("Min {0}, CutOff {1}, Max {2}, NumDivisions {3} gives a Division Size of {4}", Min, CutOff, Max, NumDivisions, size);
return size;
}
public static int Get(int min, int cutOff, int max, int numDivisions)
{
return new RangeDivider(min, cutOff, max, numDivisions).GetSize();
}
public static void Test()
{
Get(-7,0,57,4);
Get(-9, 0, 12, 4);
Get(-1, 0, 7, 6);
}
}
Min -7, CutOff 0, Max 57, NumDivisions 4 gives a Division Size of 19
Min -9, CutOff 0, Max 12, NumDivisions 4 gives a Division Size of 6
Min -1, CutOff 0, Max 7, NumDivisions 6 gives a Division Size of 2

Categories