VBA rounding issue (that's not banker's rounding) [duplicate] - vba

This question already has answers here:
VBA Double vs Single rounding
(1 answer)
Why does Bankers Rounding function in Excel VBA give different results depending on number of decimal places?
(1 answer)
Closed last month.
I'm having an issue with the Round function in VBA. I'm aware that it uses Banker's Rounding but the results still seem inconsistent to me:
? Round(1.425, 2)
1.42
? Round(2.425, 2)
2.42
? Round(3.425, 2)
3.42
? Round(4.425, 2)
4.42
? Round(5.425, 2)
5.42
? Round(6.425, 2)
6.42
? Round(7.425, 2)
7.42
? Round(8.425, 2)
8.43
? Round(9.425, 2)
9.43
? Round(10.425, 2)
10.42
? Round(11.425, 2)
11.42
? Round(12.425, 2)
12.42
If I understand Banker's Rounding, all of these should round to x.42 but 8.425 and 9.425 don't. This is in Excel 16.66 for Mac but I've verified it in other products as well.
EDIT
I confirmed the same behaviour occurs in C# as well when I use double data types. But when I use decimal, all is right again. Which leads me to believe this is an issue with floating points in VBA.

Related

Is there anything special about the number 308? [duplicate]

This question already has answers here:
Biggest integer that can be stored in a double
(10 answers)
Closed 1 year ago.
So one day I was experimenting (like any other good coder does), and I came up across this:
>>> 1e308
1e+308
>>> 1e309
inf
What is going on? First of all, 308’s factors are 2, 2, 7, and 11.
Farther investigation yields:
>>> 1.7976931348623158075e308 # No, I didn’t copy it incorrectly
1.797693134862315e+308
>>> 1.79769313486231581+308
inf
So what is going on? There doesn’t seem any relationship between an absurdly big number and an equally weird number with over 10 decimal places.
Also, all of this was using the repl python console, so others might be different.
A double-precision floating point number in IEEE-754 has an 11-bit exponent and a 53-bit mantissa. The 11-bit exponent means we get from 2**(-1023) to 2**+1023. 2**1023 happens to be 10**308.
You get about 3.23 bits per decimal digit. A 53-bit mantissa gives you about 17 digits of precision.
The largest number that fits in a double is, as you noticed, 1.7976931348623158075E+308.
I recommend https://en.wikipedia.org/wiki/IEEE_754 .

Compound formula without decimals

I am programming in Solidity and trying to write a formula to calculate a compounding amount, I can write the formula in something like Excel as:
1 * (1 + 0.0025) ^ 2212
However, this obviously doesn't work is Solidity, so I tried;
uint rate = 25;
return 1 * (1 + (rate / 10000)) ** 2212;
Which still doesn't work.. explanation in edit below.
Anyone have some guidance on how I can get this working?
Thanks!
EDIT: by doesn't work, I mean that Solidity does not support floating point numbers in any form, 25/10000 returns 0 (not 0.0025). Which then results in the whole equation returning 1 (the real answer is 250).
My assumption is that the only way I can really do this is by re-working this equation into something that doesn't involve decimals places (or very large numbers, because raising to-the-power-of quickly gets out of hand).

Mod with Float Numbers gives wrong Result [duplicate]

This question already has answers here:
VBA equivalent to Excel's mod function
(9 answers)
Closed 5 years ago.
When I try this Code:
A = 19 Mod 6.7
the Result is 5 but it should be 5.6
Can someone say me, whats going wrong?
Annoyingly, VBA will round the 6.7 to 7 as it doesn't have a floating point modulus function (cf. Java).
Effectively it evaluates 19 Mod CInt(6.7), and CInt uses German Rounding, rather than integer truncation.
If you want to duplicate the behaviour of the MOD function on a worksheet, see VBA equivalent to Excel's mod function
MOD is an integer function in VBA. It would be better to use:
a - (b * (a / b))

Calculating logarithms in vb.net - conflicting results

I am doing some calculations in vb.net, this is my equation:
rms = (20 * (Math.Log(rms / 0.7746))) 'also tried (Math.Log10(rms / 0.7746))
I have tried various different methods of writing this, including separating out the calculations into various steps. However the final result is quite far out.
I have tried declaring my variable 'rms' as a decimal and a double. It does contain decimal places.
In Excel, I have tried the same calculation using this formula:
=20*(LOG(C2/0.7746)) ' where C2 is the RMS value
And the results are consistent with a website I used to check, as well as my pocket calculator.
I have also tried rounding the number to 3 decimal places:
rms = Math.Round(rms, 3)
This too has a minimal effect on the final result.
I can only assume it's the 'operator precedence' in VB but I'm struggling to work this one out.
Any help greatly appreciated as always, thanks.
After a marathon debugging session I found an error in my code.
I have a routine that uses the voltage at a given frequency to "normalise" all the plots I do to 0dBu.
My normalisation routine was broken. Badly.
And finally - to get the correct output from the log maths, I had to change the order in which the calculation was performed.
It was originally rms = (Math.Log10(rms / 0.7746) * 20)
In trying to find the issue, I changed it to rms = (20 * (Math.Log(rms / 0.7746)))
Which yields a different (and incorrect) result.
In any case - it's fixed now.
Thanks to all who responded.

What is wrong with Math.Round() in VB.Net?

I have encountered a weird case in Math.Round function in VB.Net
Math.Round((32.625), 2)
Result : 32.62
Math.Round((32.635), 2)
Result : 32.64
I need 32.63 but the function is working in different logic in these cases.
I can get the decimal part and make what I want doing something on it. But isn't this too weird, one is rounding to higher, one is rounding to lower.
So how can I get 32.63 from 32.625 without messing with decimal part ? (as the natural logic of Maths)
Math.Round uses banker's rounding by default. You can change that by specifying a different MidPointRounding option. From the MSDN:
Rounding away from zero
Midpoint values are rounded to the next number away from zero. For
example, 3.75 rounds to 3.8, 3.85 rounds to 3.9, -3.75 rounds to -3.8,
and -3.85 rounds to -3.9. This form of rounding is represented by the
MidpointRounding.AwayFromZero enumeration member. Rounding away from
zero is the most widely known form of rounding.
Rounding to nearest, or banker's rounding
Midpoint values are rounded to the nearest even number. For example,
both 3.75 and 3.85 round to 3.8, and both -3.75 and -3.85 round to
-3.8. This form of rounding is represented by the MidpointRounding.ToEven enumeration member.
Rounding to nearest is the standard form of rounding used in financial
and statistical operations. It conforms to IEEE Standard 754, section
4. When used in multiple rounding operations, it reduces the rounding error that is caused by consistently rounding midpoint values in a
single direction. In some cases, this rounding error can be
significant.
So, what you want is:
Math.Round(32.625, 2, MidpointRounding.AwayFromZero)
Math.Round(32.635, 2, MidpointRounding.AwayFromZero)
As others have mentioned, if precision is important, you should be using Decimal variables rather than floating point types. For instance:
Math.Round(32.625D, 2, MidpointRounding.AwayFromZero)
Math.Round(32.635D, 2, MidpointRounding.AwayFromZero)
Try this (from memory):
Math.Round((32.635), 2, MidPointRounding.AwayFromZero)
Try this.
Dim d As Decimal = 3.625
Dim r As Decimal = Math.Ceiling(d * 100D) / 100D
MsgBox(r)
This should do what you want.
Hers a quick function you can add to simplify your life and make it so you don't have to type so much all the time.
Private Function roundd(dec As Decimal)
Dim d As Decimal = dec
Dim r As Decimal = Math.Ceiling(d * 100D) / 100D
Return r
End Function
Add this to your application then use the function
roundd(3.624)
or whatever you need.
to display the result - example
msgbox(roundd(3.625))
This will display a messagebox with 3.63
Textbox1.text = roundd(3.625)
this will set textbox1.text - 3.63 etc. etc.
So if you need to round more then one number, it won't be so tedious and you can save alot of typing.
Hope this helps.
You can't using floats which is what numbers like 32.625 is treated as in VB.Net. (There is also the issue of Banker's rounding as mention by #StevenDoggart - you are probably going to have to deal with both issues.)
The issue is that the number stored is not exactly what is entered because these numbers do not into a fixed binary representation e.g. 32.625 is stored as 32.62499997 and 32.635 as 32.63500001.
The only way to be exact is to store the numbers as the type Decimal
DIM num as Decimal
num = ToDecimal("32.625")