Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 8 years ago.
Improve this question
I'm trying to code a file copy program with progressbar but It crashes at percentage computing.Here is my code:
private void operation()
{
byte[] buffer = new byte[1024 * 1024];
using (streamSFD)
{
using (Stream streamOFD = new FileStream(textBox1.Text, FileMode.Open))
{
while (streamOFD.Read(buffer, 0, buffer.Length) > 0)
{
streamSFD.Write(buffer, 0, buffer.Length);
progressBar1.Value = percentage((int)streamOFD.Length, (int)streamSFD.Length);
label2.Text = streamSFD.Length.ToString() + "/" + streamOFD.Length.ToString();
label1.Text = progressBar1.Value.ToString() + "%";
}
}
}
}
private int percentage(int x, int y)
{
return (y * 100) / x;
}
From the comments to the question it became clear, that the percentage method returned negative values. How can this happen?
Note that the property Stream.Length is a long, and so is Stream.Position (which is perhaps also a property you want to use for calculating the progress percentage).
Casting a long (width of 64 bit) to an int (width of 32 bit) will truncate the long by just taking the lower 32 bits into account.
Imagine you have the following positive long value:
0x1FFFFFF00 (hex) = 8589934336 (decimal)
Casting this to int will discard the upper 32 bits, resulting in:
0xFFFFFF00 (hex) = -256 (decimal)
(In most CPU/ALU architectures, negative integer numbers are commonly represented by the two's complement of their absolute value.)
The key to fix the problem is to not truncate the long values. Since the resulting percentage value should be an int value in the range of 0...100 (it is a percentage for a progress bar), Math.Min will be utilized to cap any calculation results greater than 100 (although, for the cod given in the question the calculation result should not exceed 100).
private int percentage(long x, long y)
{
return (int) Math.Min( (y * 100) / x, 100L );
}
Now, casting Stream.Length to an int is not necessary anymore:
progressBar1.Value = percentage(streamOFD.Length, streamSFD.Length);
Related
There are a lot of similar questions asked on SO, but I've yet to find one that works and is easily portable to C#. Most involve C++ or similar, and the (presumably) working answers rely on either embedded assembly or native C/C++ functions that don't exist in C#. Several functions work for part of the range, but fail at other parts. I found one working answer I was able to port to C#, but it was very slow (turns out it's decently-fast when I compile to x64 instead of x86, so I posted it as the answer to beat).
Problem
I need a function that allows me to multiply any 64-bit integer by a fraction 0 to 1 (or -1 to 1) that is derived from two 64-bit integers. Ideally, the answer would work for both Int64 and UInt64, but it's probably not hard to make one work from the other.
In my case, I have a random 64-bit Int64/UInt64 (using the xoshiro256p algorithm, though that's likely irrelevant). I want to scale that number to any arbitrary range in the type's allowed values. For example, I might want to scale Int64 to the range [1000, 35000]. This is, conceptually, easy enough:
UInt64 minVal = 1000;
UInt64 maxVal = 35000;
UInt64 maxInt = UInt64.MaxValue;
UInt64 randInt = NextUInt64(); // Random value between 0 and maxInt.
UInt64 diff = maxVal - minVal + 1;
UInt64 scaledInt = randInt * diff / maxInt; // This line can overflow.
return scaledInt + minVal;
As noted by many other people, and the comment above, the problem is that randInt * diff can potentially overflow.
On paper, I could simply store that intermediate result in a 128-bit integer, then store the result of the division in the 64-bit output. But 128-bit math isn't native to 64-bit systems, and I'd rather avoid arbitrary-precision libraries since I'll be making lots of calls to this function and efficiency will be notable.
I could multiply by a double to get 53 bits of precision, which is fine for what I'm currently doing, but I'd rather come up with a proper solution.
I could create a C++ library with one of the ASM solutions and call that library, but I'd like something that's pure C#.
Requirements
Needs to be pure C#.
Needs to work for any set of inputs such that randInt * diff / maxInt is in the range [0, maxInt] (and each value itself is in the same range).
Shouldn't require an external library.
Needs to be +-1 from the mathematically-correct answer.
Needs to be reasonably quick. Maybe I'm just asking for miracles, but I feel like if doubles can do 5-10 ms, we should be able to hit 20 ms with purpose-built code that gets another 11 bits of precision.
Ideally works relatively well in both release and debug modes. My code has about a 3:1 ratio, so I'd think we could get debug under 5-ish times the release time.
My Testing
I've tested the following solutions for relative performance. Each test ran 1 million iterations of my random number generator, scaling using various methods. I started by generating random numbers and putting them in lists (one for signed, one for unsigned). Then I ran through each list and scaled it into a second list.
I initially had a bunch of tests in debug mode. It mostly didn't matter (we're testing relative performance), but the Int128/UInt128 libraries fared much better in release mode.
Numbers in parenthesis are the debug time. I include them here because I still want decent performance while debugging. The Int128 library, for example, is great for release mode, but terrible for debug. It might be useful to use something that has a better balance until you're ready for final release. Because I'm testing a million samples, the time in milliseconds is also the time in nanoseconds per operation (all million UInt64s get generated in 33 ms, so each one is generated in 33 ns).
Source code for my testing can be found here, on GitGub.
86 ms (267): the Int64 random generator.
33 ms (80): the UInt64 random generator.
4 ms (5): using double conversion to Int64, with reduced precision.
8 ms (10): again for UInt64.
76 ms (197): this C Code for Int64, converted to C# (exact code in my answer below).
72 ms (187): again for UInt64.
54 ms (1458): this UInt128 library, for Int64.
40 ms (1476): again for UInt64.
1446 ms (1455): double128 library for Int64. Requires a paid license for commercial use.
1374 ms (1397): again for UInt64.
I couldn't get these to give proper results.
this MulDiv64 library, linked to the main application with DllImport.
QPFloat, compiled to x64, created a MulDiv64 function in the C++ code.
this Java code.
the MFllMulDiv function from the Microsoft Media Foundation library. I tried to test it, but couldn't figure out how to get VS to link into my C++ project properly.
Similar Questions
Most accurate way to do a combined multiply-and-divide operation in 64-bit?
Answers by phuclv, Soonts, Mysticial, and 500 - Internal Server Error involve external libraries, assembly, or MSVC-specific functions.
Answers by timos, AnT, Alexey Frunze, and Michael Burr don't actually answer anything.
Answers by Serge Rogatch and Pubby aren't precise.
Answer by AProgrammer works, but is very slow (and I have no idea how it works) -- I ended up using it anyways and getting decent results in x64 compilation.
How can I descale x by n/d, when x*n overflows?
The only answer, by Abhay Aravinda, isn't real code, I wasn't sure how to implement the last section, and the comments suggest it can overflow for large values anyways.
Fast method to multiply integer by proper fraction without floats or overflow
Answers by Taron and chux - Reinstate Monica are approximations or MSVC-specific.
Answer by R.. GitHub STOP HELPING ICE just uses 64-bit math since that question is about multiplying Int32.
(a * b) / c MulDiv and dealing with overflow from intermediate multiplication
Answer by Jeff Penfold didn't work for me (I think I'm missing something in the logical operators converting from Java to C#), and it was very slow.
Answer by greybeard looks nice, but I wasn't sure how to translate it to C#.
Answers by tohoho and Dave overflow.
Answer by David Eisenstat requires BigInt libraries.
How to multiply a 64 bit integer by a fraction in C++ while minimizing error?
All the answers overflow in different circumstances.
But 128-bit math isn't native to 64-bit systems
While that is mostly true, there is a decent way to get the full 128-bit product of two 64-bit integers: Math.BigMul (for .NET 5 and later)
x64 has a corresponding division with a 128-bit input, and such a pair of full-multiply followed by a wide-division would implement this "scale integer by a proper fraction" operation (with the limitation that the fraction must not be greater than 1, otherwise an overflow could result). However, C# doesn't have access to wide division, and even if it did, it wouldn't be very efficient on most hardware.
But you can just use BigMul directly too, because the divisor should really be 264 to begin with (not 264 - 1), and BigMul automatically divides by 264.
So the code becomes: (not tested)
ulong ignore;
ulong scaled = Math.BigMul(randInt, diff, out ignore);
return scaled + minVal;
For older versions of .NET, getting the high 64 bits of the product could be done like this:
static ulong High64BitsOfProduct(ulong a, ulong b)
{
// decompose into 32bit blocks (in ulong to avoid casts later)
ulong al = (uint)a;
ulong ah = a >> 32;
ulong bl = (uint)b;
ulong bh = b >> 32;
// low times low and high times high
ulong l = al * bl;
ulong h = ah * bh;
// cross terms
ulong x1 = al * bh;
ulong x2 = ah * bl;
// carry from low half of product into high half
ulong carry = ((l >> 32) + (uint)x1 + (uint)x2) >> 32;
// add up all the parts
return h + (x1 >> 32) + (x2 >> 32) + carry;
}
Unfortunately that's not as good as Math.BigMul, but at least there is still no division.
I was able to get down to about 250 ms using AProgrammer's C code by telling the compiler to NOT prefer 32-bit code using the AnyCpu setup.
In release mode, the PRNG takes up about 5 ms (I somewhat doubt this; I think it's being optimized out when I try to just run the PRNG), and the total is down to about 77ms.
I'm still not sure how it works, but the linked answer says the code has some redundant operations for base 10 support. I'm thinking I can reduce the time even further by optimizing out the base 10 support, if I knew how it worked enough to do that.
The Int64 (signed) is a little slower (78 vs 77ms release, about 20ms slower debug), but I'm basically the same speed. It does fail if min=Int64.MinValue and max=Int64.MaxValue, returning min every time, but works for every other combination I could throw at it.
The signed math is less useful for straight scaling. I just made something that worked in my use case. So I made a conversion that seems to work for the general signed case, but it could probably be optimized a bit.
Unsigned scaling algorithm, converted to C#.
/// <summary>
/// Returns an accurate, 64-bit result from value * multiplier / divisor without overflow.
/// From https://stackoverflow.com/a/8757419/5313933
/// </summary>
/// <param name="value">The starting value.</param>
/// <param name="multiplier">The number to multiply by.</param>
/// <param name="divisor">The number to divide by.</param>
/// <returns>The result of value * multiplier / divisor.</returns>
private UInt64 MulDiv64U(UInt64 value, UInt64 multiplier, UInt64 divisor)
{
UInt64 baseVal = 1UL << 32;
UInt64 maxdiv = (baseVal - 1) * baseVal + (baseVal - 1);
// First get the easy thing
UInt64 res = (value / divisor) * multiplier + (value % divisor) * (multiplier / divisor);
value %= divisor;
multiplier %= divisor;
// Are we done?
if (value == 0 || multiplier == 0)
return res;
// Is it easy to compute what remain to be added?
if (divisor < baseVal)
return res + (value * multiplier / divisor);
// Now 0 < a < c, 0 < b < c, c >= 1ULL
// Normalize
UInt64 norm = maxdiv / divisor;
divisor *= norm;
value *= norm;
// split into 2 digits
UInt64 ah = value / baseVal, al = value % baseVal;
UInt64 bh = multiplier / baseVal, bl = multiplier % baseVal;
UInt64 ch = divisor / baseVal, cl = divisor % baseVal;
// compute the product
UInt64 p0 = al * bl;
UInt64 p1 = p0 / baseVal + al * bh;
p0 %= baseVal;
UInt64 p2 = p1 / baseVal + ah * bh;
p1 = (p1 % baseVal) + ah * bl;
p2 += p1 / baseVal;
p1 %= baseVal;
// p2 holds 2 digits, p1 and p0 one
// first digit is easy, not null only in case of overflow
UInt64 q2 = p2 / divisor;
p2 = p2 % divisor;
// second digit, estimate
UInt64 q1 = p2 / ch;
// and now adjust
UInt64 rhat = p2 % ch;
// the loop can be unrolled, it will be executed at most twice for
// even baseVals -- three times for odd one -- due to the normalisation above
while (q1 >= baseVal || (rhat < baseVal && q1 * cl > rhat * baseVal + p1))
{
q1--;
rhat += ch;
}
// subtract
p1 = ((p2 % baseVal) * baseVal + p1) - q1 * cl;
p2 = (p2 / baseVal * baseVal + p1 / baseVal) - q1 * ch;
p1 = p1 % baseVal + (p2 % baseVal) * baseVal;
// now p1 hold 2 digits, p0 one and p2 is to be ignored
UInt64 q0 = p1 / ch;
rhat = p1 % ch;
while (q0 >= baseVal || (rhat < baseVal && q0 * cl > rhat * baseVal + p0))
{
q0--;
rhat += ch;
}
// we don't need to do the subtraction (needed only to get the remainder,
// in which case we have to divide it by norm)
return res + q0 + q1 * baseVal; // + q2 *baseVal*baseVal
}
MulDiv64 uses the unsigned version to get a signed conversion. It's slower in my use case (290ms vs 260ms debug, 95ms vs 81ms release), but works for the general case. Doesn't work for Int64.MinValue (raises an exception: "Negating the minimum value of a twos complement number is invalid.").
public static Int64 MulDiv64(Int64 value, Int64 multiplier, Int64 divisor)
{
// Get the signs then convert to positive values.
bool isPositive = true;
if (value < 0) isPositive = !isPositive;
UInt64 val = (UInt64)Math.Abs(value);
if (multiplier < 0) isPositive = !isPositive;
UInt64 mult = (UInt64)Math.Abs(multiplier);
if (divisor < 0) isPositive = !isPositive;
UInt64 div = (UInt64)Math.Abs(divisor);
// Scaledown.
UInt64 scaledVal = MulDiv64U(val, mult, div);
// Convert to signed Int64.
Int64 result = (Int64)scaledVal;
if (!isPositive) result *= -1;
// Finished.
return result;
}
GetRangeU function returns an unsigned UInt64 between min and max, inclusive. Scaling is straight from the earlier function.
/// <summary>
/// Returns a random unsigned integer between Min and Max, inclusive.
/// </summary>
/// <param name="min">The minimum value that may be returned.</param>
/// <param name="max">The maximum value that may be returned.</param>
/// <returns>The random value selected by the Fates for your application's immediate needs. Or their fickle whims.</returns>
public UInt64 GetRangeU(UInt64 min, UInt64 max)
{
// Swap inputs if they're in the wrong order.
if (min > max)
{
UInt64 Temp = min;
min = max;
max = Temp;
}
// Get a random integer.
UInt64 randInt = NextUInt64();
// Fraction randInt/MaxValue needs to be strictly less than 1.
if (randInt == UInt64.MaxValue) randInt = 0;
// Get the difference between min and max values.
UInt64 diff = max - min + 1;
// Scale randInt from the range 0, maxInt to the range 0, diff.
randInt = MulDiv64U(diff, randInt, UInt64.MaxValue);
// Add the minimum value and return the result.
return randInt;// randInt + min;
}
GetRange function returns a signed Int64 between min and max. Not easily convertible to general scaling, but it's faster than the method above in this case.
/// <summary>
/// Returns a random signed integer between Min and Max, inclusive.
/// Returns min if min is Int64.MinValue and max is Int64.MaxValue.
/// </summary>
/// <param name="min">The minimum value that may be returned.</param>
/// <param name="max">The maximum value that may be returned.</param>
/// <returns>The random value selected.</returns>
public Int64 GetRange(Int64 min, Int64 max)
{
// Swap inputs if they're in the wrong order.
if (min > max)
{
Int64 Temp = min;
min = max;
max = Temp;
}
// Get a random integer.
UInt64 randInt = NextUInt64();
// Fraction randInt/MaxValue needs to be strictly less than 1.
if (randInt == UInt64.MaxValue) randInt = 0;
// Get the difference between min and max values.
UInt64 diff = (UInt64)(max - min) + 1;
// Scale randInt from the range 0, maxInt to the range 0, diff.
randInt = MulDiv64U(diff, randInt, UInt64.MaxValue);
// Convert to signed Int64.
UInt64 randRem = randInt % 2;
randInt /= 2;
Int64 result = min + (Int64)randInt + (Int64)randInt + (Int64)randRem;
// Finished.
return result;
}
This question already has answers here:
Why does integer division in C# return an integer and not a float?
(8 answers)
Closed 1 year ago.
I am trying to use a function in windows form application that convert a given point to another coordinate system. However, I encountered a strange problem. The input are correct but output is always 0. First, I thought it caused because of the local variables and then instead of variables I used only integers but it did not solve. I have no idea about it. Here the code and output basically:
string[] newPoint1 = convertPoints(X1, Y1);
string[] convertPoints(int oldX, int oldY)
{
//int newX = ((oldX - oldLeft) / (oldRight - oldLeft)) * (newRight - newLeft);
MessageBox.Show(oldX.ToString()); // output is 296
int newX = (oldX / 500) * 4096; // ????????????????????? (296/500) * 4096 = 0 ?????????????
MessageBox.Show(newX.ToString()); // here output is 0
int newY = newTop + ((oldY - oldTop) / (oldBottom - oldTop)) * (newBottom - newTop);
//MessageBox.Show(newY.ToString());
string[] newPoints = {newX.ToString(), newY.ToString()};
//MessageBox.Show(newPoints[0], newPoints[1]);
return newPoints;
}
This is working as it should. Because oldX is an Integer, when you divide it, it rounds (drops anything after the decimal). I would convert it to float and back into an integer, like so
int newX = (int)(((float)oldX / 500) * 4096);
This will preserve the whole number until you're done at the end. You'll also need to do the same for the Y values
An integer division cuts off the decimal places. So in your case, 296/500 you would expect 0.592. As integer has no decimal places, it cuts off them off resulting in 0.
Change the oldX to double and divide by 500.0
You are getting 0 because oldX/500 is a fraction usually and since you are using the int datatypes there can only be whole numbers. What I would recommend doing is changing the data type then rounding yourself.
//Old code
int newX = (1 / 500);
Console.WriteLine(newX);
// writes 0 to console
//New code
double newXD = (1 / 500.0) * 4096;
Console.WriteLine(newXD);
//Writes 8.192
The 1 and the 500 are considered ints try
Console.WriteLine(1/500);
It writes 0 to the console.
Console.WriteLine(1/500.0);
Console.WriteLine((float)1/500);
Console.WriteLine((double)1/500);
All these write 8.192 to the console.
Then after you have the double or other more accurate data type consider rounding if you really want an int.
Alright, I'm trying to calculate the percentage of two values. This should be really simple but for some weird reason it's not working. I'm too tired/dumb to figure it out.
Here's my code, it keeps returning 0, i checked the values while debugging and with FilesCompleted being 295 and TotalFilesCount being 25002 the returnvalue var is just 0, it should be 1 already.
private int CalculatePercentComplete(int FilesCompleted, int TotalFilesCount)
{
int returnvalue = (FilesCompleted / TotalFilesCount) * 100;
if (returnvalue > 100 || returnvalue < 1) return 1;
else return returnvalue;
}
i checked the values while debugging and with FilesCompleted being 295 and TotalFilesCount being 25002 the returnvalue var is just 0, it should be 1 already.
No, because all the arithmetic is being done with integers. So first this expression is evaluated:
(FilesCompleted / TotalFilesCount)
That's 295 / 25002. The result of that integer arithmetic is 0... and when you then multiply it by 100, you've still got 0. The simplest fix is just to do the multiplication first:
int returnvalue = (FilesCompleted * 100) / TotalFilesCount;
Note that that will overflow if FilesCompleted is greater than int.MaxValue / 100. You could fix that by either doing everything in floating point arithmetic:
int returnvalue = (int)((FilesCompleted * 100.0) / TotalFilesCount);
... or by using long integer arithmetic:
int returnvalue = (int)((FilesCompleted * 100L) / TotalFilesCount);
Neither of these are necessary if you don't expect to have an insane number of files, of course. (You're fine up to 42 million files...)
As a side note, your parameter names violate .NET naming conventions. They should be camelCased - totalFilesCount and filesCompleted.
How about
int returnvalue = (int)(((double)FilesCompleted / TotalFilesCount) * 100);
What this is doing
Converting int FilesCompleted to double. For eg if its 295, then this will convert it into 295.0 so that division happens in double.
There is no need to convert TotalFilesCount to double also as divison of double by integer (or integer by double) returns a double.
So the returned double result is 0.011799056075513958 which is multipled by 100
So the retunred result is 1.1799056075513958 which is finally converted to int which returns 1
The FilesCompleted/TotalFilesCount returns 0.01 which in int format is 0, try FilesCompleted*100/TotalFilesCount!
Indeed, simple error, when doing diversions with int, the answer will be an int. Your answer would be between 0 and 1 so rounded down it is 0 (int).
Use:
int returnvalue = (int)((FilesCompleted / (double)TotalFilesCount) * 100);
To make your calculation use a double for the fractional number and then multiply that by 100 and cast that to an int.
This question already has answers here:
C# is rounding down divisions by itself
(10 answers)
C# double not working as expected [duplicate]
(1 answer)
Closed 7 years ago.
I have c# program that calculates percentage and returns int value, but it always returns 0.
I have been writing code for 16 constitutive hours so I appreciate if you find the mistakes within it.
I debugged my code and I found that the value is being passed correctly.
private int returnFlag(int carCapacity, int subscribers)
{
int percentage = (subscribers / carCapacity)*100;
return percentage;
}
What you're seeing is the result of operating on two integers, and losing the fractional portion.
This piece of code, when using the values 5 and 14, will truncate to 0:
(subscribers / carCapacity)
You need to cast one of the operands to a double or decimal:
private int returnFlag(int carCapacity, int subscribers)
{
decimal percentage = ((decimal)subscribers / carCapacity) * 100;
return (int)percentage;
}
The issue is that since you're performing math on int (read: integer) values, any fractions or remainders get thrown out. This can be seen by changing your code to
int percentage = (subscribers / carCapacity);
percentage *= 100;
Since (subscribers / carCapacity) results in less than one, the only possible number an int can hold is 0 - and 0 * 100 is 0.
You can fix this by converting to a more precise number, such as double, before performing operations:
private int returnFlag(int carCapacity, int subscribers)
{
double percentage = ((double)subscribers / (double)carCapacity) * 100.0;
return (int)percentage;
}
Integer types (int) don't work with fractions. Change the types you are working with in your division to decimal, double, single, or float.
Alright, I'm trying to calculate the percentage of two values. This should be really simple but for some weird reason it's not working. I'm too tired/dumb to figure it out.
Here's my code, it keeps returning 0, i checked the values while debugging and with FilesCompleted being 295 and TotalFilesCount being 25002 the returnvalue var is just 0, it should be 1 already.
private int CalculatePercentComplete(int FilesCompleted, int TotalFilesCount)
{
int returnvalue = (FilesCompleted / TotalFilesCount) * 100;
if (returnvalue > 100 || returnvalue < 1) return 1;
else return returnvalue;
}
i checked the values while debugging and with FilesCompleted being 295 and TotalFilesCount being 25002 the returnvalue var is just 0, it should be 1 already.
No, because all the arithmetic is being done with integers. So first this expression is evaluated:
(FilesCompleted / TotalFilesCount)
That's 295 / 25002. The result of that integer arithmetic is 0... and when you then multiply it by 100, you've still got 0. The simplest fix is just to do the multiplication first:
int returnvalue = (FilesCompleted * 100) / TotalFilesCount;
Note that that will overflow if FilesCompleted is greater than int.MaxValue / 100. You could fix that by either doing everything in floating point arithmetic:
int returnvalue = (int)((FilesCompleted * 100.0) / TotalFilesCount);
... or by using long integer arithmetic:
int returnvalue = (int)((FilesCompleted * 100L) / TotalFilesCount);
Neither of these are necessary if you don't expect to have an insane number of files, of course. (You're fine up to 42 million files...)
As a side note, your parameter names violate .NET naming conventions. They should be camelCased - totalFilesCount and filesCompleted.
How about
int returnvalue = (int)(((double)FilesCompleted / TotalFilesCount) * 100);
What this is doing
Converting int FilesCompleted to double. For eg if its 295, then this will convert it into 295.0 so that division happens in double.
There is no need to convert TotalFilesCount to double also as divison of double by integer (or integer by double) returns a double.
So the returned double result is 0.011799056075513958 which is multipled by 100
So the retunred result is 1.1799056075513958 which is finally converted to int which returns 1
The FilesCompleted/TotalFilesCount returns 0.01 which in int format is 0, try FilesCompleted*100/TotalFilesCount!
Indeed, simple error, when doing diversions with int, the answer will be an int. Your answer would be between 0 and 1 so rounded down it is 0 (int).
Use:
int returnvalue = (int)((FilesCompleted / (double)TotalFilesCount) * 100);
To make your calculation use a double for the fractional number and then multiply that by 100 and cast that to an int.