Multiplication of large numbers represented as arrays? - c#

The numbers are stored in the arrays with their digits in reverse order. Here is a functions that should multiply two numbers, lhs and rhs, and store the product in result:
public static void MultiplyDigitArrays(int[] lhs, int[] rhs, int[] result)
{
int length1 = Math.Max(lhs.Length, rhs.Length);
for (int i = 0; i < length1; i++)
{
int[] PartialProduct = new int[result.Length];
int length2 = Math.Min(lhs.Length, rhs.Length);
for (int j = 0; j < length2; j++)
{
int multiplicand = (lhs.Length < rhs.Length) ? rhs[i] : lhs[i];
int multiplier = (lhs.Length < rhs.Length) ? lhs[j] : rhs[j];
int product = PartialProduct[i + j] + multiplicand * multiplier;
PartialProduct[i + j] = product % 10;
int carry = product / 10;
PartialProduct[i + j + 1] = PartialProduct[i + j + 1] + carry;
}
SumDigitArrays(PartialProduct, result, result);
}
}
However, if I multiply:
static void Main(string[] args)
{
int[] n1 = { 1, 1 };
int[] n2 = { 1, 1 };
int[] result = new int[Math.Max(n1.Length, n2.Length) * 2 + 1];
MultiplyDigitArrays(n1, n2, result);
PrintArray(result);
Console.WriteLine();
}
the result is:
00132
instead of the expected:
00121
What am I doing wrong?
For the MCVE:
public static void PrintArray(int[] Array)
{
int length = Array.Length;
for (int i = length - 1; i >= 0; i--)
{
Console.Write(Array[i]);
}
}
public static void SumDigitArrays(int[] a, int[] b, int[] result)
{
int length = Math.Max(a.Length, b.Length);
for (int i = 0; i < length; i++)
{
int lhs = (i < a.Length) ? a[i] : 0;
int rhs = (i < b.Length) ? b[i] : 0;
int sum = result[i] + lhs + rhs;
result[i] = sum % 10;
int carry = sum / 10;
if (i + 1 < result.Length)
{
result[i + 1] = result[i + 1] + carry;
}
}
}

The reason is because the third parameter use you in calling SumDigitArrays should be empty. Instead, you feed it the result variable which contains data on any iteration other than the first.
Implement your method like this:
public static int[] MultiplyDigitArrays(int[] lhs, int[] rhs)
{
int length1 = Math.Max(lhs.Length, rhs.Length);
var result = new int[length1* length1];
for (int i = 0; i < length1; i++)
{
int[] PartialProduct = new int[length1 * length1];
int length2 = Math.Min(lhs.Length, rhs.Length);
for (int j = 0; j < length2; j++)
{
int multiplicand = (lhs.Length < rhs.Length) ? rhs[i] : lhs[i];
int multiplier = (lhs.Length < rhs.Length) ? lhs[j] : rhs[j];
int product = PartialProduct[i + j] + multiplicand * multiplier;
PartialProduct[i + j] = product % 10;
int carry = product / 10;
PartialProduct[i + j + 1] = PartialProduct[i + j + 1] + carry;
}
result = SumDigitArrays(PartialProduct, result);
}
return result;
}
public static int[] SumDigitArrays(int[] a, int[] b)
{
int length = Math.Max(a.Length, b.Length);
var result = new int[length];
for (int i = 0; i < length; i++)
{
int lhs = (i < a.Length) ? a[i] : 0;
int rhs = (i < b.Length) ? b[i] : 0;
int sum = result[i] + lhs + rhs;
result[i] = sum % 10;
int carry = sum / 10;
if (i + 1 < result.Length)
{
result[i + 1] = result[i + 1] + carry;
}
}
return result;
}

I don't exactly understand the logic you are performing, but
int product = PartialProduct[i + j] + multiplicand * multiplier;
Gets evaluated as
int product = PartialProduct[i + j] + (multiplicand * multiplier);
Did you intend it to do
int product = (PartialProduct[i + j] + multiplicand) * multiplier;
As that could explain your error.

Apart from the two other answers given (which are spot-on and solve your problem), unless you have a very specific need, I'd recommend going for BigInteger if you need to multiply very large numbers.
For your specific needs (in case your numbers must come and go in an array of ints, which is a weird way to store any number), your Multiply could become:
public static void MultiplyDigitArrays(int[] lhs, int[] rhs, int[] result)
{
var n1 = BigInteger.Parse(string.Join("", lhs));
var n2 = BigInteger.Parse(string.Join("", rhs));
var resultBi = BigInteger.Multiply(n1, n2);
Array.Clear(result, 0, result.Length);
var stResult = resultBi.ToString().PadLeft(result.Length, '0');
for(int i = 0; i < stResult.Length; i++)
{
result[(stResult.Length-1)-i] = int.Parse(stResult[i].ToString());
}
}
Note that the burden of this function is actually converting your integer array back and forth, since an integer array is a weird format to store a number.
If you work directly with strings (or BigIntegers), this function would just not be necessary. For example, if working with strings containing the numbers, this could become:
public static string MultiplyBigNumbers(string lhs, string rhs)
{
var n1 = BigInteger.Parse(lhs);
var n2 = BigInteger.Parse(rhs);
return BigInteger.Multiply(n1, n2).ToString();
}
And just call it: MultiplyBigNumbers("3242", "42349");
Then again, I'd recommend just working with BigInteger all the way down, and have it converted whenever you need to store it (for which a byte array makes more sense, and you can get it with ToByteArray()) or display (which can be easily done with a ToString() call)
Note that passing an array for the result is also pretty weird (for .NET anyway), since you don't need the original values. You'd be better off returning an array and calculating the needed length in the function itself, not having the caller figure it out.

Related

How to fix this implementaion of the Merge Sort in c#

I've read the CLRS and tried to implement the recursive merge sort algorithm . cant see what the error is but everytime i run it gives me an "Index out of bounds error "
i've been trying for 5h now
static public void MergeSort(int[] input, int IndexStanga, int IndexDreapta)
{
if (IndexStanga < IndexDreapta)
{
int IndexMijloc = (IndexDreapta + IndexStanga) / 2;
MergeSort(input, IndexStanga, IndexMijloc);
MergeSort(input, IndexMijloc + 1, IndexDreapta);
Merge(input, IndexStanga, IndexDreapta, IndexMijloc);
}
}
static public void Merge(int[] input, int stanga, int dreapta, int mijloc)
{
int lungDR = 0;
int lunST = 0;
lungDR = dreapta - mijloc;
lunST = mijloc - stanga + 1;
int[] valDreapta = new int[lungDR + 1];
int[] valStanga = new int[lunST + 1];
valDreapta[valDreapta.Length - 1] = int.MaxValue;
valStanga[valStanga.Length - 1] = int.MaxValue;
int i = 0;
int j = 0;
for (i = stanga; i <= mijloc; i++) valStanga[i] = input[i];
for (i = 0; i < lungDR; i++) { valDreapta[i] = input[i + mijloc + 1]; }
i = 0;
j = 0;
for (int k = 0; k < input.Length; k++)
{
if (valStanga[i] <= valDreapta[j]) //error out of bounds
{
input[k] = valStanga[i];
i++;
}
else
{
input[k] = valDreapta[j];
j++;
}
}
}
Fixes noted in comments below. First fix for moving data from input to valStanga. Second fix for the range on merging back to input. The parameters for merge are in an unusual order, first, last, middle. Normally the order is first, middle, last.
Comments: The program will have issues if the array to be sorted contains elements equal to max integer. It would be more efficient to do a one time allocation of a working array, rather than allocate new sub-arrays on every call to merge. The copy operations can be avoided by changing the direction of merge with each level of recursion.
int i = 0;
int j = 0;
for (i = 0; i < lungDR; i++) { valDreapta[i] = input[i + mijloc + 1]; }
for (i = 0; i < lunST; i++) { valStanga[i] = input[i + stanga]; } // fix
i = 0;
j = 0;
for (int k = stanga; k <= dreapta; k++) // fix
{
if (valStanga[i] <= valDreapta[j])

Sequence of marching chars in 2 strings

I have to write searching algorithm, For example I have to compare str="giorgi" to str2="grigol". I'm trying to find longest matching sequence of chars, so that the order of chars is the same and string which I should get is "grg"... with this c# code I'm getting "grig".
int k=0;
string s="";
string str = "giorgi";
string str2 = "grigol";
for(int i=0;i<str.Length;i++)
{
for (int j = k; j < str2.Length; j++)
{
if (str[i] == str2[j])
{
s += str2[k];
k++;
goto endofloop;
}
}
endofloop:;
}
Console.WriteLine(s);
The solution:
using System;
class GFG
{
/* Returns length of LCS for X[0..m-1], Y[0..n-1] */
static int lcs( char[] X, char[] Y, int m, int n )
{
int [,]L = new int[m+1,n+1];
/* Following steps build L[m+1][n+1]
in bottom up fashion. Note
that L[i][j] contains length of
LCS of X[0..i-1] and Y[0..j-1] */
for (int i = 0; i <= m; i++)
{
for (int j = 0; j <= n; j++)
{
if (i == 0 || j == 0)
L[i, j] = 0;
else if (X[i - 1] == Y[j - 1])
L[i, j] = L[i - 1, j - 1] + 1;
else
L[i, j] = GFG.max(L[i - 1, j], L[i, j - 1]);
}
}
return L[m, n];
}
static int max(int a, int b)
{
return (a > b)? a : b;
}
}
And now the program to test it:
public static void Main()
{
String s1 = "giorgi";
String s2 = "grigol";
char[] X=s1.ToCharArray();
char[] Y=s2.ToCharArray();
int m = X.Length;
int n = Y.Length;
Console.Write("Length of LCS is" + " " +lcs( X, Y, m, n ) );
}
}

Get longest substring between two strings

I have two words,
britanicaeng and
britanicahin
I need to find out the longest common word between these i.e, britanica.
How can I do this in C# ?
Try this method:
public static string FindLongestCommonSubstring(string s1, string s2)
{
int[,] a = new int[s1.Length + 1, s2.Length + 1];
int row = 0; // s1 index
int col = 0; // s2 index
for (var i = 0; i < s1.Length; i++)
for (var j = 0; j < s2.Length; j++)
if (s1[i] == s2[j])
{
int len = a[i + 1, j + 1] = a[i, j] + 1;
if (len > a[row, col])
{
row = i + 1;
col = j + 1;
}
}
return s1.Substring(row - a[row, col], a[row, col]);
}
Usage example:
Console.WriteLine(FindLongestCommonSubstring("britanicaeng", "britanicahin"));
I refactored the C++ code from Ashutosh Singh at https://iq.opengenus.org/longest-common-substring-using-rolling-hash/ to create a rolling hash approach in C# - this will find the substring in O(N * log(N)^2) time and O(N) space
using System;
using System.Collections.Generic;
public class RollingHash
{
private class RollingHashPowers
{
// _mod = prime modulus of polynomial hashing
// any prime number over a billion should suffice
internal const int _mod = (int)1e9 + 123;
// _hashBase = base (point of hashing)
// this should be a prime number larger than the number of characters used
// in my use case I am only interested in ASCII (256) characters
// for strings in languages using non-latin characters, this should be much larger
internal const long _hashBase = 257;
// _pow1 = powers of base modulo mod
internal readonly List<int> _pow1 = new List<int> { 1 };
// _pow2 = powers of base modulo 2^64
internal readonly List<long> _pow2 = new List<long> { 1L };
internal void EnsureLength(int length)
{
if (_pow1.Capacity < length)
{
_pow1.Capacity = _pow2.Capacity = length;
}
for (int currentIndx = _pow1.Count - 1; currentIndx < length; ++currentIndx)
{
_pow1.Add((int)(_pow1[currentIndx] * _hashBase % _mod));
_pow2.Add(_pow2[currentIndx] * _hashBase);
}
}
}
private class RollingHashedString
{
readonly RollingHashPowers _pows;
readonly int[] _pref1; // Hash on prefix modulo mod
readonly long[] _pref2; // Hash on prefix modulo 2^64
// Constructor from string:
internal RollingHashedString(RollingHashPowers pows, string s, bool caseInsensitive = false)
{
_pows = pows;
_pref1 = new int[s.Length + 1];
_pref2 = new long[s.Length + 1];
const long capAVal = 'A';
const long capZVal = 'Z';
const long aADif = 'a' - 'A';
unsafe
{
fixed (char* c = s)
{
// Fill arrays with polynomial hashes on prefix
for (int i = 0; i < s.Length; ++i)
{
long v = c[i];
if (caseInsensitive && capAVal <= v && v <= capZVal)
{
v += aADif;
}
_pref1[i + 1] = (int)((_pref1[i] + v * _pows._pow1[i]) % RollingHashPowers._mod);
_pref2[i + 1] = _pref2[i] + v * _pows._pow2[i];
}
}
}
}
// Rollingnomial hash of subsequence [pos, pos+len)
// If mxPow != 0, value automatically multiply on base in needed power.
// Finally base ^ mxPow
internal Tuple<int, long> Apply(int pos, int len, int mxPow = 0)
{
int hash1 = _pref1[pos + len] - _pref1[pos];
long hash2 = _pref2[pos + len] - _pref2[pos];
if (hash1 < 0)
{
hash1 += RollingHashPowers._mod;
}
if (mxPow != 0)
{
hash1 = (int)((long)hash1 * _pows._pow1[mxPow - (pos + len - 1)] % RollingHashPowers._mod);
hash2 *= _pows._pow2[mxPow - (pos + len - 1)];
}
return Tuple.Create(hash1, hash2);
}
}
private readonly RollingHashPowers _rhp;
public RollingHash(int longestLength = 0)
{
_rhp = new RollingHashPowers();
if (longestLength > 0)
{
_rhp.EnsureLength(longestLength);
}
}
public string FindCommonSubstring(string a, string b, bool caseInsensitive = false)
{
// Calculate max neede power of base:
int mxPow = Math.Max(a.Length, b.Length);
_rhp.EnsureLength(mxPow);
// Create hashing objects from strings:
RollingHashedString hash_a = new RollingHashedString(_rhp, a, caseInsensitive);
RollingHashedString hash_b = new RollingHashedString(_rhp, b, caseInsensitive);
// Binary search by length of same subsequence:
int pos = -1;
int low = 0;
int minLen = Math.Min(a.Length, b.Length);
int high = minLen + 1;
var tupleCompare = Comparer<Tuple<int, long>>.Default;
while (high - low > 1)
{
int mid = (low + high) / 2;
List<Tuple<int, long>> hashes = new List<Tuple<int, long>>(a.Length - mid + 1);
for (int i = 0; i + mid <= a.Length; ++i)
{
hashes.Add(hash_a.Apply(i, mid, mxPow));
}
hashes.Sort(tupleCompare);
int p = -1;
for (int i = 0; i + mid <= b.Length; ++i)
{
if (hashes.BinarySearch(hash_b.Apply(i, mid, mxPow), tupleCompare) >= 0)
{
p = i;
break;
}
}
if (p >= 0)
{
low = mid;
pos = p;
}
else
{
high = mid;
}
}
// Output answer:
return pos >= 0
? b.Substring(pos, low)
: string.Empty;
}
}

Rewrite Recursive algorithm more simply - Euler 15

I would like to rewrite the functionality of this algorithm (which I used to solve ProjectEuler problem 15) in a non recursive way.
Yes, I realise there are many better ways to solve the actual problem, but as a challenge I would like to simplify this logic as much as possible.
public class SolveRecursion
{
public long Combination = 0;
public int GridSize;
public void CalculateCombination(int x = 0, int y = 0)
{
if (x < GridSize)
{
CalculateCombination(x + 1, y);
}
if (y < GridSize)
{
CalculateCombination(x, y + 1);
}
if (x == GridSize && y == GridSize)
Combination++;
}
}
And tests:
[Test]
public void SolveRecursion_GivenThree_GivesAnswerOf20Routes()
{
solveRecursion.GridSize = 3;
solveRecursion.CalculateCombination();
var result = solveRecursion.Combination;
Assert.AreEqual(20, result);
}
[Test]
public void SolveRecursion_GivenFour_GivesAnswerOf70Routes()
{
solveRecursion.GridSize = 4;
solveRecursion.CalculateCombination();
var result = solveRecursion.Combination;
Assert.AreEqual(70, result);
}
EDIT: Here is another simple function written in both ways:
//recursion
private int Factorial(int number)
{
if (number == 0)
return 1;
int returnedValue = Factorial(number - 1);
int result = number*returnedValue;
return result;
}
//loop
private int FactorialAsLoop(int number)
{
//4*3*2*1
for (int i = number-1; i >= 1; i--)
{
number = number*i;
}
return number;
}
Any hints would be greatly appreciated. I've tried dynamic programming solution (which uses a more maths based approach), and an equation to successfully solve the puzzle.
I wonder - can this first algorithm be made non recursive, simply?
The non-recursive solution is:
const int n = 4;
int a[n + 2][n + 2] = {0};
a[0][0] = 1;
for (int i = 0; i < n + 1; ++i)
for (int j = 0; j < n + 1; ++j) {
a[i][j + 1] += a[i][j];
a[i + 1][j] += a[i][j];
}
std::cout << a[n][n] << std::endl;
Just for information, this problem should have been solved on the paper, the answer for NxM grid is C(N+M,N), where C is the combination function - http://en.wikipedia.org/wiki/Combination

Java Integer.ValueOf method equivalence in C# With Radix Parameter

My task is to migrate this Java code to a C# version, but I'm having trouble with the ValueOf method, since I can't seem to find a equivalent version for C# (because of the Radix parameter used on Java, 16 in this case).
public String decrypt_string(String s)
{
String s1 = "";
int i = s.length() / 2;
int[] ai = new int[i];
for (int j = 0; j < i; j++)
{
// This is the "problematic" line \/
ai[j] = Integer.valueOf(s.substring(j * 2, j * 2 + 2), 16).intValue();
}
int[] ai1 = decrypt_block(ai, i);
for (int k = 0; k < i; k++)
{
if (ai1[k] != 0)
s1 = s1 + (char)ai1[k];
}
return s1;
}
Here is my try, but it failed:
public String decrypt_string(String s)
{
String s1 = "";
int i = s.Length / 2;
int[] ai = new int[i];
for (int j = 0; j < i; j++)
{
int startIndex = j * 2;
string tmp = s.Substring(startIndex, 2);
ai[j] = Int32.Parse (tmp);
}
int[] ai1 = decrypt_block(ai, i);
for (int k = 0; k < i; k++)
{
if (ai1[k] != 0)
s1 = s1 + (char)ai1[k];
}
return s1;
}
Thanks in advance
If you are trying to parse a hexadecimal (base-16) number, use this:
int.Parse (tmp, NumberStyles.HexNumber);
You need to convert a string to an integer, given that the string is in a specific base.
int i = Convert.ToInt32(str, 16);
int j = Convert.ToInt32("A", 16); // 10
So:
for (int j = 0; j < i; j++)
{
int startIndex = j * 2;
ai[j] = Convert.ToInt32(s.Substring(startIndex, 2));
}
The radix is on Integer.valueOf(), not s.substring() in the java code you show there, so this would become:
ai[j] = Int32.Parse(s.Substring(j * 2, j * 2 + 2), 16);

Categories

Resources