Mandatory decimal numbers Math Round [closed] - c#

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 2 months ago.
Improve this question
I have a method that returns the perimeter of a triangle. One of the parameters to this method is the precision.
When I call my function specifying the precision I don't get the results I expect. I don't know how I can resolve the problem with Math.Round.
public static double TrianglePerimeter(int a, int b, int c, int precision = 2)
{
if (a < 0 || b < 0 || c < 0 || precision < 2 || precision > 8)
throw new ArgumentException("wrong arguments");
if (a + b < c || a + c < b || b + c < a)
throw new ArgumentException("object not exist");
return Math.Round((double)a+(double)b+(double)c, precision);
}
Example:
a = 1, b = 2, c = 3, precision = 3
Result = 6.000
a = 1, b = 1, c = 1, precision = 5
Result = 3.00000

As others have pointed out, decimal rounding won't get you what you need because 12 = 12.0 = 12.000. The Round function will only work for you if you actually have significant digits that extend to those decimal places (e.g. 12.0011 would round to 12.001 if you did Math.Round(12.0011, 3);
What you need to do is format the return value as a string with the proper format. Notice the return result is string, not double. Something like this:
public static string TrianglePerimeterS(int a, int b, int c, int precision = 2)
{
if (a < 0 || b < 0 || c < 0 || precision < 2 || precision > 8)
throw new ArgumentException("wrong arguments");
if (a + b < c || a + c < b || b + c < a)
throw new ArgumentException("object not exist");
// Build the format string in the format of "0.000" if precision is 3
string formatString = "0." + new string('0', precision);
double value = Math.Round((double)a + (double)b + (double)c, precision);
string result = value.ToString(formatString);
return result;
}

As the people before me have mentioned, you won't get those extra decimal places through Round() if no significant numbers extend to those decimal places.
One way of getting the answer in that format is how #John C. did it:
https://stackoverflow.com/a/74724870/19433977
I think you need to modify your function's mathematical part to be more correct.
//Changed input parameters corresponding to sides as double instead of int to cover more cases
public static string TrianglePerimeter(double a, double b, double c, int precision)
{
//Used "<=" instead of "<" because the sides can't be 0 either
if (a <= 0 || b <= 0 || c <= 0 || precision < 2 || precision > 8)
throw new ArgumentException("Wrong arguments");
//Used "<=" instead of "<" because the sum of sides can't be equal to the 3rd side either
if (a + b <= c || a + c <= b || b + c <= a)
throw new ArgumentException("Triangle can't exist");
string format = "0." + new string('0', precision);
double value = Math.Round(a + b + c, precision);
string result = value.ToString(format);
return result;
}

Related

How to perform addition of 2 very large (over 50 digits) binary string values in C#

I have been thinking of adding binary numbers where binary numbers are in a form of string and we add those two binary numbers to get a resultant binary number (in string).
So far I have been using this:
long first = Convert.ToInt64(a, 2);
long second = Convert.ToInt64(b, 2);
long addresult = first + second;
string result = Convert.ToString(addresult, 2);
return result;
Courtesy of Stackoverflow: Binary addition of 2 values represented as strings
But, now I want to add numbers which are far greater than the scope of a long data type.
For Example, a Binary value whose decimel result is a BigInteger, i.e., incredibly huge integers as shown below:
111101101000010111101000101010001010010010010110011010100001000010110110110000110001101 which equals to149014059082024308625334669
1111001101011000001011000111100011101011110100101010010001110101011101010100101000001101000010000110001110100010011101011111111110110101100101110001010101011110001010000010111110011011 which equals to23307765732196437339985049250988196614799400063289798555
At least I think it does.
Courtesy of Stackoverflow:
C# Convert large binary string to decimal system
BigInteger to Hex/Decimal/Octal/Binary strings?
I have used logic provided in above links which are more or less perfect.
But, is there a more compact way to add the given two binary strings?
Kindly let me know as this question is rattling in my mind for some time now.
You can exploit the same scheme you used before but with BigInteger:
using System.Linq;
using System.Numerics;
...
BigInteger first = a.Aggregate(BigInteger.Zero, (s, item) => s * 2 + item - '0');
BigInteger second = b.Aggregate(BigInteger.Zero, (s, item) => s * 2 + item - '0');
StringBuilder sb = new StringBuilder();
for (BigInteger addresult = first + second; addresult > 0; addresult /= 2)
sb.Append(addresult % 2);
if (sb.Length <= 0)
sb.Append('0');
string result = string.Concat(sb.ToString().Reverse());
This question was a nostalgic one - thanks. Note that my code is explanatory and inefficient with little to no validation, but it works for your example. You definitely do not want to use anything like this in a real world solution, this is just to illustrate binary addition in principle.
BinaryString#1
111101101000010111101000101010001010010010010110011010100001000010110110110000110001101
decimal:149014059082024308625334669
BinaryString#2
1111001101011000001011000111100011101011110100101010010001110101011101010100101000001101000010000110001110100010011101011111111110110101100101110001010101011110001010000010111110011011
decimal:23307765732196437339985049250988196614799400063289798555
Calculated Sum
1111001101011000001011000111100011101011110100101010010001110101011101010100101000001101000010001101111011100101011010100101010000000111111000100100101001100110100000111001000100101000
decimal:23307765732196437339985049251137210673881424371915133224
Check
23307765732196437339985049251137210673881424371915133224
decimal:23307765732196437339985049251137210673881424371915133224
Here's the code
using System;
using System.Linq;
using System.Numerics;
namespace ConsoleApp3
{
class Program
{
// return 0 for '0' and 1 for '1' (C# chars promotion to ints)
static int CharAsInt(char c) { return c - '0'; }
// and vice-versa
static char IntAsChar(int bit) { return (char)('0' + bit); }
static string BinaryStringAdd(string x, string y)
{
// get rid of spaces
x = x.Trim();
y = y.Trim();
// check if valid binaries
if (x.Any(c => c != '0' && c != '1') || y.Any(c => c != '0' && c != '1'))
throw new ArgumentException("binary representation may contain only '0' and '1'");
// align on right-most bit
if (x.Length < y.Length)
x = x.PadLeft(y.Length, '0');
else
y = y.PadLeft(x.Length, '0');
// NNB: the result may require one more bit than the longer of the two input strings (carry at the end), let's not forget this
var result = new char[x.Length];
// add from least significant to most significant (right to left)
var i = result.Length;
var carry = '0';
while (--i >= 0)
{
// to add x[i], y[i] and carry
// - if 2 or 3 bits are set then we carry '1' again (otherwise '0')
// - if the number of set bits is odd the sum bit is '1' otherwise '0'
var countSetBits = CharAsInt(x[i]) + CharAsInt(y[i]) + CharAsInt(carry);
carry = countSetBits > 1 ? '1' : '0';
result[i] = countSetBits == 1 || countSetBits == 3 ? '1' : '0';
}
// now to make this byte[] a string
var ret = new string(result);
// remember that final carry?
return carry == '1' ? carry + ret : ret;
}
static BigInteger BigIntegerFromBinaryString(string s)
{
var biRet = new BigInteger(0);
foreach (var t in s)
{
biRet = biRet << 1;
if (t == '1')
biRet += 1;
}
return biRet;
}
static void Main(string[] args)
{
var s1 = "111101101000010111101000101010001010010010010110011010100001000010110110110000110001101";
var s2 = "1111001101011000001011000111100011101011110100101010010001110101011101010100101000001101000010000110001110100010011101011111111110110101100101110001010101011110001010000010111110011011";
var sum = BinaryStringAdd(s1, s2);
var bi1 = BigIntegerFromBinaryString(s1);
var bi2 = BigIntegerFromBinaryString(s2);
var bi3 = bi1 + bi2;
Console.WriteLine($"BinaryString#1\n {s1}\n decimal:{bi1}");
Console.WriteLine($"BinaryString#2\n {s2}\n decimal:{bi2}");
Console.WriteLine($"Calculated Sum\n {sum}\n decimal:{BigIntegerFromBinaryString(sum)}");
Console.WriteLine($"Check\n {bi3}\n decimal:{bi3}");
Console.ReadKey();
}
}
}
I'll add an alternative solution alongside AlanK's just as an example of how you might go about this without converting the numbers to some form of integer before adding them.
static string BinaryStringAdd(string b1, string b2)
{
char[] c = new char[Math.Max(b1.Length, b2.Length) + 1];
int carry = 0;
for (int i = 1; i <= c.Length; i++)
{
int d1 = i <= b1.Length ? b1[^i] : 48;
int d2 = i <= b2.Length ? b2[^i] : 48;
int sum = carry + (d1-48) + (d2-48);
if (sum == 3)
{
sum = 1;
carry = 1;
}
else if (sum == 2)
{
sum = 0;
carry = 1;
}
else
{
carry = 0;
}
c[^i] = (char) (sum+48);
}
return c[0] == '0' ? String.Join("", c)[1..] : String.Join("", c);
}
Note that this solution is ~10% slower than Alan's solution (at least for this test case), and assumes the strings arrive to the method formatted correctly.

C#. Count Consecutive 1 bits in ulong [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 6 years ago.
Improve this question
Basically i want to count the number of consecutive 1 bits (1 bit groups) in a ulong. for example:
ulong x = 0x1BD11BDAA9FC1A22UL;
In binary it becomes: 1101111010001000110111101101010101001111111000001101000100010.
I need output as No of consecutive 1 bits = 16.
Convert to bitstring, split at 0 character while removing empty entries, count the number of groups.
static void Main()
{
long x = 0x1BD11BDAA9FC1A22;
var bitstring = Convert.ToString(x, 2) ;
Console.WriteLine("Bitstring: " + bitstring);
var oneBitGroups = bitstring.Split(new char[]{'0'}, StringSplitOptions.RemoveEmptyEntries).Length;
Console.WriteLine("The number of 1 bit groups is: " + oneBitGroups);
}
Output:
Bitstring: 1101111010001000110111101101010101001111111000001101000100010
The number of 1 bit groups is: 16
You can do that with bitshift and counting each time the least significant bit is 1 and the previous wasn't.
public static int BitGroupCount(long num)
{
int count = 0;
bool prevOne = false;
while (num != 0)
{
bool currOne = (num & 1) == 1;
if (currOne && !prevOne)
count++;
num = num >> 1;
prevOne = currOne;
}
return count;
}
If you run
Console.WriteLine(BitGroupCount((long)0x1BD11BDAA9FC1A22UL));
You will get 16 as the result
Something like this to get the value as a binary string then :
int consecutive = 0;
char? previous = null;
foreach (char c in str)
{
if (previous != null)
{
if (previous.Equals('1') && c.Equals('1'))
{
consecutive++;
}
}
previous = c;
}
return consecutive;
I think i found the solution based on Hamming Weight (thanks to PetSerAl):
public static int no_of_consecutive_one_bits(ulong x)
{
x = (x & ~(x << 1));
x -= (x >> 1) & 0x5555555555555555;
x = (x & 0x3333333333333333) + ((x >> 2) & 0x3333333333333333);
x = (x + (x >> 4)) & 0x0f0f0f0f0f0f0f0f;
return ((int)((x * 0x0101010101010101) >> 56));
}
Some explanation: The x & ~(x<<1) is basically isolating the last bit in each "group". The rest is the Hamming Weight algorithm for summing the number of non-zero bits.
This should work:
ulong x = 0x1BD11BDAA9FC1A22UL;
bool last = false;
int count = 0;
for(int i = sizeof(ulong)*8-1; i >= 0; i--)
{
var c = x & (1UL<<i);
if(c != 0 && !last)
count ++;
last = c != 0;
}
count should be 16

Finding highest value in array however with assigned numbers to characters

i have a quick question
A = 10
B = 11
C = 12
D = 13
I have an char array
"5623ADCB"
I would want to find the biggest value which is D = 13 but the program doesn't recognize D = 13 when i use a for loop to look for the biggest number. Instead it outputs the D's ascii value, how do i make ensure that everytime a D is encountered, it would be recognized as 13 and not it's ascii value?
Thanks guys for your help
functional recipe: make a map from Char to Int - use Max:
static int Map(char c)
{
return Int32.Parse (c.ToString(), System.Globalization.NumberStyles.HexNumber);
}
var max = "5623ADCB".Select (Map).Max ();
get's you 13 in this case ;)
here is a version if you are concerned with memory and performance:
static int FindMax(string s)
{
s = s.ToUpper ();
var max = 0;
for (int i = 0; i < s.Length; i++) {
var v = Map (s [i]);
if (v > max)
max = v;
}
return max;
}
static int Map(char c)
{
if (c >= '0' && c <= '9')
return (int)c - (int)'0';
if (c >= 'A' && c <= 'E')
return (int)c - (int)'A' + 10;
throw new ArgumentOutOfRangeException ();
}
btw: I have no clue why you want 14 if you want D to be 13 - if the first was a typo then you have to change the Map function above (a switch will do if you don't want to get fancy) - as your first definition was exactly the same you would assume from Hex I went with it.
Do you need to get the greater value?
var array = "5623ADCB".ToCharArray();
Console.WriteLine(array.Max());
Or, to make sure "D" gets translated to "13", transform it from hexadecimal:
var array = "5623ADCB".ToCharArray();
Console.WriteLine(Convert.ToInt32(array.Max().ToString(), 16));
Notice the Convert.ToInt32(string, int) method, which receives the numeric base to translate the string expression.

Find least significant digit position of C# decimal

I would like to find the least significant digit position of C# decimal and set a 1 in that position and zero in all other positions.
So for example for 2m the result would be 1m.
For 34m the result would be 1m.
For 0.4m it would return 0.1m.
For 1200m I would want 100m.
How do I do this?
Can I use something similar to https://stackoverflow.com/a/757266/246622 ?
(Edit: I removed the confusing 2.0m, added result for 1200)
You could take advantage of an implementation detail of Decimal, its exponent is equal to the number of significant digits in the fraction. You can obtain the value of the exponent with the GetBits() method. Which makes this (rather obscure) code work:
public static Decimal SignificantFraction(Decimal d) {
var b = decimal.GetBits(d);
return new decimal(1, 0, 0, false, (byte)((b[3] >> 16) & 0x7fff));
}
Note that this even works in corner-cases like 0.0m, it produces 0.1m. You didn't specify what should happen to negative values so I punted for false in the constructor. Replace it with d < 0 if you want the result to be negative.
How about something along these lines?
decimal number = 1200m;
decimal result = 1;
decimal tmp = number;
while (tmp % 1 != 0)
{
result /= 10;
tmp *= 10;
}
if (result > 0 && number != 0)
{
tmp = number;
while (tmp % 10 == 0)
{
result *= 10;
tmp /= 10;
}
}
Edit: So with the 1200 example added my solution is not as neat anymore... But I think it should do the trick
var t = 1.11111000m;
//var t = 134000m;
var tr = t.ToString().Reverse().ToArray();
char[] ca;
if (t % 1 > 0)
ca = tr.SkipWhile(c => c == '0').Select((c, i) => i == 0 ? '1' : c == ',' ? ',' : '0').Reverse().ToArray();
else
{
ca = tr.TakeWhile((c, i) => c == '0' || tr[i - 1] == '0').Reverse().ToArray();
ca[0] = '1';
}
var result = decimal.Parse(new string(ca));

How do I determine if adding 2 numbers will involve regourping / carryover or subracting 2 numbers will involve borrowing?

I need to create a function that will generate 2 random numbers between x and y (e.g. x = 1, y = 20) which when added will not involve regrouping / carryover or which when subracted will not involve borrowing.
For example,
18 + 1 = good
14 + 5 = good
18-7 = good
29 - 8 = good
15 + 6 = bad
6 + 7 = bad
21 - 3 = bad
36 - 8 = bad etc.
I want to create a simple worksheet generator that will generate sample problems using the requirements above.
I guess I could always convert the number to string, get the right most digit for each of the 2 numbers, convert them back to integer, and test if one is greater than the other. Repeat for all the digit. Only thing is, that is so damn ugly (read inefficient). I am sure that there is a better way. Anyone have any suggestions? Thanks
Generate them one digit at a time. e.g
a1 = rand(9)
a2 = rand(9 - a1)
b1 = rand(9)
b2 = rand(9 - b1)
x = b1*10 + a1
y = b2*10 + a2
From the construction you know that x+y will not involve any carry, because a1+a2 <= 9 and b1 + b2 <= 9.
You can do similar for subtraction.
If you want to restrict the overall range to be [1..20] instead of [1..99], just adjust the range for the leftmost digit:
b1 = rand(1)
b2 = rand(1 - b1)
using System;
class Sample {
static void Main() {
var rnd = new Random();
var x = 1;
var y = 20;
var a = rnd.Next(x, y);
var b = rnd.Next(x, y);
var op = '+';
Console.WriteLine("{0} {2} {1} = {3}", a, b, op , isValid(a, b, op)? "good":"bad");
op = '-';
Console.WriteLine("{0} {2} {1} = {3}", a, b, op , isValid(a, b, op)? "good":"bad");
}
static bool isValid(int x, int y, char op){
int a = x % 10;
int b = y % 10;
switch (op){
case '+':
return a + b < 10;
case '-':
return x >= y && a - b >= 0;
default:
throw new Exception(String.Format("unknown operator '{0}'", op));
}
}
}
Breaking up the numbers into digits is indeed exactly what you need to do. It does not matter whether you do that by arithmetic manipulation (division and modulus by 10) or by converting the numbers into strings, but fundamentally your question is precisely about the individual digits of the numbers.
For the subtraction x − y, no borrows are required if and only if none of the digits in y are greater than the corresponding digit in x.
For the addition x + y, there will be no carries if and only if the sum of each pair of corresponding digits is less than 10.
Here's some pseudo-C# for checking these conditions:
bool CanSubtractWithoutBorrow (uint x, uint y) {
while (y > 0) {
if ((x % 10) < (y % 10)) return False;
x /= 10; y /= 10;
}
return True;
}
bool CanAddWithoutCarry (uint x, uint y) {
while (x > 0 && y > 0) {
if ((x % 10) + (y % 10) >= 10) return False;
x /= 10; y /= 10;
}
return True;
}
You need to look at each pair digit in turn, and see if adding or subtracting them involves carries.
You can get the rightmost digit by taking the value modulo 10, x%10, and you can erase the right most digit by dividing by 10.
No string conversions are necessary.

Categories

Resources