Dividing variables of type long long to get a percentage? - objective-c

So I am trying to divide two variables that are type long long, totalBytesWritten and totalBytesExpected
Basically I am trying to figure out the percentage complete my file upload is and update the progressbar accordingly.
For example, I am sending 262144 of 1839948 bytes
But when I do double progress = totalBytesWritten/totalBytesExpected it gives me some unexpected numbers. When I NSLog progress I get only 0s and then finally 1.
Thanks!

You're performing an integer division, then the result is getting casted to a double but it's too late: you already lost precision.If you just cast one of the two operands to a double, the other one will be also promoted to a double and you'll get a floating point value as result:
NSLog(#"%f,"(double)totalBytesWritten/totalBytesExpected);

long long is a non-decimal data type, so it uses integer division. Thus, since totalBytesWritten is probably (hopefully) less than totalBytesExpected, you'll always get 0. Try converting them to double first, then divide.

Related

Objective C, division between floats not giving an exact answer

Right now I have a line of code like this:
float x = (([self.machine micSensitivity] - 0.0075f) / 0.00025f);
Where [self.machine micSensitivity] is a float containing the value 0.010000
So,
0.01 - 0.0075 = 0.0025
0.0025 / 0.00025 = 10.0
But in this case, it keeps returning 9.999999
I'm assuming there's some kind of rounding error but I can't seem to find a clean way of fixing it. micSensitivity is incremented/decremented by 0.00025 and that formula is meant to return a clean integer value for the user to reference so I'd rather get the programming right than just adding 0.000000000001.
Thanks.
that formula is meant to return a clean integer value for the user to reference
If that is really important to you, then why do you not multiply all the numbers in this story by 10000, coerce to int, and do integer arithmetic?
Or, if you know that the answer is arbitrarily close to an integer, round to that integer and present it.
Floating-point arithmetic is binary, not decimal. It will almost always give rounding errors. You need to take that into account. "float" has about six digit precision. "double" has about 15 digits precision. You throw away nine digits precision for no reason.
Now think: What do you want to display? What do you want to display if the result of your calculation is 9.999999999? What would you want to display if the result is 9.538105712?
None of the numbers in your question, except 10.0, can be exactly represented in a float or a double on iOS. If you want to do float math with those numbers, you will have rounding errors.
You can round your result to the nearest integer easily enough:
float x = rintf((self.machine.micSensitivity - 0.0075f) / 0.00025f);
Or you can just multiply all your numbers, including the allowed values of micSensitivity, by 4000 (which is 1/0.00025), and thus work entirely with integers.
Or you can change the allowed values of micSensitivity so that its increment is a fraction whose denominator is a power of 2. For example, if you use an increment of 0.000244140625 (which is 2-12), and change 0.0075 to 0.00732421875 (which is 30 * 2-12), you should get exact results, as long as your micSensitivity is within the range ±4096 (since 4096 is 212 and a float has 24 bits of significand).
The code you have posted is correct and functioning properly. This is a known side effect of using floating point arithmetic. See the wiki on floating point accuracy problems for a dull explanation as to why.
There are several ways to work around the problem depending on what you need to use the number for.
If you need to compare two floats, then most everything works OK: less than and greater than do what you would expect. The only trouble is testing if two floats are equal.
// If x and y are within a very small number from each other then they are equal.
if (fabs(x - y) < verySmallNumber) { // verySmallNumber is usually called epsilon.
// x and y are equal (or at least close enough)
}
If you want to print a float, then you can specify a precision to round to.
// Get a string of the x rounded to five digits of precision.
NSString *xAsAString = [NSString stringWithFormat:#"%.5f", x];
9.999999 is equal 10. there is prove:
9.999999 = x then 10x = 99.999999 then 10x-x = 9x = 90 then x = 10

Convert.ToSingle() from double in vb.net returns wrong value

Here is my question :
If we have the following value
0.59144706948010461
and we try to convert it to Single we receive the next value:
0.591447055
As you can see this is not that we should receive. Could you please explain how does this value get created and how can I avoid this situation?
Thank you!
As you can see this is not that we should receive.
Why not? I strongly suspect that's the closest Single value to the Double you've given.
From the documentation for Single, having fixed the typo:
All floating-point numbers have a limited number of significant digits, which also determines how accurately a floating-point value approximates a real number. A Single value has up to 7 decimal digits of precision, although a maximum of 9 digits is maintained internally.
Your Double value is 0.5914471 when limited to 7 significant digits - and so is the Single value you're getting. Your original Double value isn't exactly 0.59144706948010461 either... the exact values of the Double and Single values are:
Double: 0.5914470694801046146693579430575482547283172607421875
Single: 0.591447055339813232421875
It's important that you understand a bit about how binary floating point works - see my articles on binary floating point and decimal floating point for more background.
When converting from double to float you're also rounding. The result should be the single-precision number that is closest to the number you are rounding.
That is exactly what you're getting here.
Floating-point numbers between 0.5 and 1 are of the form n / 2^24 where n is between 2^23 and 2^24.
0.59144706948010461... = 9922835.23723472274456576... / 2^24
so the closest single-precision floating-point number is
9922835 / 2^24 = 0.5914470553...

VB.NET Single data type calculation issue

I want to perform a basic calculation with fractional numbers using vb.net.
Dim a As Single= 7200.5
Dim b As Single= 7150.3
Dim c As Single= a - b
'Expected result = 50.2
MsgBox(a.ToString + " - " + b.ToString + " = " + c.ToString.Trim)
'Produced result is: 50.2002
Dim single1 As Single
Dim single2 As Single
Dim single3 As Single
single1 = 425000
single2 = 352922.2
single3 = single1 - single2
'Expected result is: 72077.8
MsgBox(single3.ToString)
'Produced result is: 72077.81
How can the results be so inaccurate for such a simple calculation? The problem is solved when I change the data type to Decimal, but Decimal objects consume more memory (16 bytes). Is there any alternative data type that i can use to perform simple fractional calculations with accurate results?
This is to do with the way floating point numbers are stored in memory, and a Single in .Net is a single precision floating point number, which is much less accurate than a Decimal or a Double for storing decimal numbers.
When the computer calculates your number, it only has binary fractions to use and in a single precision floating point number, they're not very accurate.
See http://en.wikipedia.org/wiki/Single-precision_floating-point_format for more information.
EDIT: There's some more information specific to VB.Net here: http://msdn.microsoft.com/en-us/library/ae382yt8(v=vs.110).aspx
The Single and Double data types are not precise. They use the floating point method to store their values. Floating points use less memory and allow for faster calculations, but they are imprecise. That is the trade-off that you have to accept if you are going to use them. If precision is important, then they are not an option for you. Decimal is precise (to a certain number of fractional digits, that is), so usually, that is the best choice for precise fractional numbers in most cases. If you really need to save memory, and you are guaranteed that your numbers will be within a certain range, then you could use an Int16, Int32, or Int64 instead. For instance, if you only care about two fractional digits, you could simply multiply everything by 100 and then just divide by 100 (using Decimal types for the division) before displaying it. In that way, you can store many numbers and perform many operations using less memory, and only need to use the Decimal data type when you need to display a result.
Dim a As Integer = 720050 '7200.5
Dim b As Integer = 715030 '7150.3
Dim c As Integer = a - b
Dim cDisplay As Decimal = CDec(c) / CDec(100)
MessageBox.Display(String.Format("{0} - {1} = {2}", a, b, c))
You can use the Decimal data type instead. It will work great! This is because Decimal is a fixed point value, whereas Single and Double are floating point values (with loss of precision).

Using Doubles in Unix?

I am calling sysctl() to retrieve mem stats and for the void* oldVal argument, I am passing in a pointer to a double. However instead of setting the double to the correct value, it just sets it to 0.00000
However, when I try doing the exact same thing with a long, it sets it to the correct stat. Why is the double being set to 0.00000 while long is being set to the correct stat?
int systemInfoNeeded[2] = {CTL_HW, HW_PHYSMEM};
size_t sizeOfBuffer = sizeof(totalAmount);
if (sysctl(systemInfoNeeded, 2, &totalAmount, &sizeOfBuffer, NULL, 0))
{
NSLog(#"Total memory stat retrieval failed.\n");
exit (EXIT_FAILURE);
}
totalAmount is a double. The second I change the type of totalAmount to long, it works perfectly. Is there anyway I can get the double to work? I want to directly send in totalAmount rather than sending a long and then assigning the value to totalAmount.
I am using Objective-C/C, on Mac OS X Snowleopard with Xcode 3.2.6
You can't just choose your favorite data type and pass a pointer to it; the sysctl call expects a pointer to an integer, and so that's what you have to provide. If you pass a pointer to a double, then you get a double with bits that represent a value as a integer -- the result is gibberish.
sysctl() accepts a pointer to the type specified, in the manpage, for the property you are querying. The parameter is declared as a void* so that the same generic interface can work with the different types expected by the various properties. That does not mean that you can use any type you want. In the case of HW_PHYSMEM, it is an integer, i.e. an int, not a long or anything else.
The only reason it works if you pass a long is because macs are little endian, thus the first four bytes of a value as a long are the same as the value as an int, but you should of course not depend on this.
If you want to read a double, convert the integer.
You should take a good look at sysctl(3). Look in particular at the example with KERN_MAXPROC.

Misunderstanding of Long data type in VBA

From the help for the Overflow Error in VBA, there's the following examples:
Dim x As Long
x = 2000 * 365 ' gives an error
Dim x As Long
x = CLng(2000) * 365 ' fine
I would have thought that, since the Long data type is supposed to be able to hold 32-bit numbers, that the first example would work fine.
I ask this because I have some code like this:
Dim Price as Long
Price = CLng(AnnualCost * Months / 12)
and this throws an Overflow Error when AnnualCost is 5000 and Months is 12.
What am I missing?
2000 and 365 are Integer values. In VBA, Integers are 16-bit signed types, when you perform arithmetic on 2 integers the arithmetic is carried out in 16-bits. Since the result of multiplying these two numbers exceeds the value that can be represented with 16 bits you get an exception. The second example works because the first number is first converted to a 32-bit type and the arithmetic is then carried out using 32-bit numbers. In your example, the arithmetic is being performed with 16-bit integers and the result is then being converted to long but at that point it is too late, the overflow has already occurred. The solution is to convert one of the operands in the multiplication to long first:
Dim Price as Long
Price = CLng(AnnualCost) * Months / 12
The problem is that the multiplication is happening inside the brackets, before the type conversion. That's why you need to convert at least one of the variables to Long first, before multiplying them.
Presumably you defined the variables as Integer. You might consider using Long instead of Integer, partly because you will have fewer overflow problems, but also because Longs calculate (a little) faster than Integers on 32 bit machines. Longs do take more memory, but in most cases this is not a problem.
In VBA, literals are integer by default (as mentioned). If you need to force a larger datatype on them you can recast them as in the example above or just append a type declaration character. (The list is here: http://support.microsoft.com/kb/191713) The type for Long is "&" so you could just do:
Price = CLng(AnnualCost * Months / 12&)
And the 12 would be recast as a long. However it is generally good practice to avoid literals and use constants. In which case you can type the constant in it's declaration.
Const lngMonths12_c as Long = 12
Price = CLng(AnnualCost * Months / lngMonths12_c)