why vba shows answer "0" when Google shows "11.05"?
Sub test2()
Debug.Print 22.15 Mod 11.1
End Sub
Q: Is it possible to get in VBA result the same as Google provide?
UPD2:VBA's Mod operator (not function) differs significantly from Excels MOD function is a few respects. First, it handles negative values differently... second, if you use 1 as the divisor, it will return 0, not the decimal portion of the floating point number... third, it handles floating point number differently (it uses Banker's Rounding to round all floating point number to whole numbers before performing it operation on those numbers whereas Excel doesn't).
As Mod in VBA only deals with integers, you'll have to scale your values, for example with 10 ^ 3 (1000) if you have values of three decimals or less:
DecimalCount = 3
Scaling = 10 ^ DecimalCount
Debug.Print (22.15 * Scaling Mod 11.1 * Scaling) / Scaling
11.05
Debug.Print (22.15 * Scaling Mod 11.075 * Scaling) / Scaling
0
Just adjust DecimalCount to match your expected values.
An alternative to Gustav's answer that doesn't need the scaling: First make an regular division, use the integer part of the result (integer quotient) and subtract the divisor times the (integer) quotient from the dividend.
Function ModDouble(a As Double, b As Double) As Double
Dim y As Double
y = (a / b)
ModDouble = a - (b * Int(y))
End Function
Testing it:
Sub test()
Debug.Print ModDouble(5, 3)
Debug.Print ModDouble(22.15, 11.1)
End Sub
> 2
> 11.05
Related
So what I am trying to do is take the difference between two values(x) and (y) to get (n). I then want to run (x) through a formula (n) times incrementing (x) each time. Then I want to output the sum all of those results into a cell. Cant figure out how to do it neatly within one cell like normal, so I've turned to VBA for once.
Here is what I have so far:
Sub Math()
'
'Math
'
Dim i As Integer
i = 0
Do While i < ((E42) - (d42))
cell(h42).Value = ((((d42) + i) ^ 2) * 100) / 3
End Sub
What I'm stuck on is how to get the result of each loop and sum them all together. I expect to have an i value that can range anywhere from 1-100. The only way I can think that would definitely work is messy where i would have a large number of cells in a column set aside that will calculate each of the iterations individually, then sum all of those together.
Alternatively, if theres a way to write a function that can calculate the sum(n) of ((x+n)^2)*100/3 then that would be much nicer but I cant think of how it would be written.
Here is how you can make a function (which can be used directly in worksheet formulas) to form a sum:
Function eval_sum(n As Long, x As Double) As Double
Dim s As Double, i As Long
For i = 0 To n - 1
s = s + (x + i) ^ 2
Next i
eval_sum = s * 100 / 3
End Function
This function evaluates:
100/3 * (x^2 + (x+1)^2 + (x+2)^2 + ... + (x+(n-1))^2)
It wasn't completely clear if this is what you were trying to do. If not, you can tweak the code to fit your needs.
Small point: I used Long rather than Integer. Forget that Integer exists. It is really legacy from the days of limited memory and 16-bit computers. In modern Excel an Integer is stored with 32 bits anyway. You are just risking overflow for no good reason.
In this code snippet below, the value of temp_int2 is 1, makes no sense to me. --> log(1000) = 3, that is log of base 10, the log function is base 'e'.
im not sure if its the "INT" function which problematic but could someone please assist.
temp_int2 = Int(Log(1000) / Log(10)) - 1
'temp_int2 = Int(Log(cap_dec) / Log(10)) - 1
MsgBox ("Value of log functuon -->" & CStr(Log(cap_dec) / Log(10)) & " value after log function " & CStr(temp_int2))
Instead of the Int function use the cLng function. While Int will cut off decimals, cLng will round to a Long.
Example Int will cut off
Int(99.2) '= 99
Int(99.5) '= 99
Int(99.8) '= 99
but cLng will round
cLng(99.2) '= 99
cLng(99.5) '= 100
cLng(99.8) '= 100
since computers and calculators calculate numeric and not algebraic there is probably a precision issue in calculation and Log(1000) / Log(10) is not exactly an algebraic 3 but a numeric 3 that is something like 2.99999999999998 which Int will cut off to 2 but cLng will round to 3.
Note that Excel is a numeric calculation program and values of type Double are not exact values. The decimals are (as with any standard calculator too) only calculated up to a defined precision.
So a Double type 3 is not a 3 but something very close to 3 like 2.99999999999998. So the Log function returns a Double and also a devision Log(1000) / Log(10) returns a Double and this is not exactly 3 but very close to 3.
Note that this is not a bug but in the nature of numeric calculations which are never exact but only precise, while algebraic calculations can be exact.
The same problem occurs when comparing values of type Double:
If DoubleA = DoubleB Then 'might not work
Here you need to use something like
If (DoubleA - DoubleB) ^ 2 < (10^ - Digits)^2
where Digits is the number of digits that need to be the same. Example
DoubleA = 0.9999999999
DoubleB = 1.0000000001
then Digits needs to be <= 9 to consider them as equal.
If you need to do that often then it comes handy to use a function for that:
Option Explicit
Public Function IsDoubleValueTheSame(DoubleA As Double, DoubleB As Double, Optional Digits As Long = 12) As Boolean
IsDoubleValueTheSame = (DoubleA - DoubleB) ^ 2 < (10 ^ -Digits) ^ 2
End Function
and call it like
Debug.Print IsDoubleValueTheSame(0.9999999999, 1.0000000001, 9) 'true
Debug.Print IsDoubleValueTheSame(0.9999999999, 1.0000000001, 10) 'false
So to come back to your initial example:
Debug.Print Log(1000) / Log(10) = 3 'false
Debug.Print IsDoubleValueTheSame(Log(1000) / Log(10), 3, 15) 'true
Debug.Print IsDoubleValueTheSame(Log(1000) / Log(10), 3, 16) 'false
which means Log(1000) / Log(10) is actually 3 precise up to 15 digits and the 16ᵗʰ digit is different.
Further information about this:
Numeric precision in Microsoft_Excel (Wikipedia)
Floating-point arithmetic may give inaccurate results in Excel (Microsoft documentation)
Compare double in VBA precision problem (Stack Overflow)
I am trying to perform some bit-shifting operations to convert 0110 0100 0000 to 1100 1000 in VBA code. This example is a decimal value of 200.
I have tried the following code but it seems like the >> is not working. Also, how do I set the data type to zero to clear all bits?
If wordmsg is a 32-bit word, How can I set bit 30 and bit 31 equal to 1?
Sub test()
'Declaring variables
Dim simvalue As Integer, wordmsg As Integer, test As Integer, resolution As Integer
simvalue= 200
resolution = 0.0625
wordmsg = simvalue / resolution
test = wordmsg >> 3
End sub
There's no bit shift operator in VBA. You can, generally speaking, multiply, divide, AND and OR your way around.
Excel exposes the Bitand, Bitlshift, Bitor, Bitrshift and Bitxor functions to VBA through Application.WorksheetFunction.
Example: test = Application.WorksheetFunction.Bitrshift(wordmsg, 3).
To manipulate 32-bit words in VBA, you can't use the Long type, because its most significant bit (MSB, bit 31) holds the sign (negative when set). Attempting to set bit 31 with e.g. myLong = 2 ^ 31 will result in an overflow. You can use the Double type as a stand-in dword, and the Application.WorksheetFunction.Bit[...] functions will work with up to 48 bits (2^48 - 1; decimal 281474976710655).
Sub BitRightShiftTest()
Dim d As Double
d = (2 ^ 31) + (2 ^ 30) + (200 / 0.0625)
Debug.Print d
d = Application.WorksheetFunction.Bitrshift(d, 3)
Debug.Print d
End Sub
Try BITRSHIFT function. http://www.excelfunctions.net/excel-bitrshift-function.html. If not available, use multiplication instead.
I've seen multiple answers say the following algorithm works fine to generate a random number between two values. I'm getting spurious results where I'll sometimes get a value returned that is higher than the upper bound.
Dim random as Integer
random = Int (3 - 0 + 1) * Rnd + 0
Debug.Print random
This should give values between 0 - 3 right? I'm seeing 0 to 4 when run a few times..???
This is one of the idiosyncrasies of VBA.
You can see the effect more clearly by writing
random = Int(4) * Rnd
4 * Rnd is a floating point double type, and when it gets assigned to random, The same rounding convention as for CInt is applied1; i.e. if Int(4) * Rnd is 3.5 or greater, the result is 4.
The fix is to write
random = Int(4 * Rnd)
1 The convention "round half to even" is often called Banker's Rounding. See
https://en.wikipedia.org/wiki/Rounding#Round_half_to_even
I think it is to be expected when explicitly converting floating point number to integer, but what might not be expected is that the rounding is towards the closest even number:
Dim i As Integer
i = 3.5 ' i = 4
i = "2.5" ' i = 2
I have user input in two cells, named "UpperRangeHigh" and "UpperRangeLow". I have the following code:
dRangeUpper = [UpperRangeHigh] - [UpperRangeLow]
lLines = Int(dRangeUpper * 100 / lInterval)
The user inputs 120.3 and 120 into the input cells respectively. lInterval has the value 10. VBA produces the result of 2 for lLines, instead of 3.
I can overcome this problem by adding 0.000000001 to dRangeUpper, but I'm wondering if there is a known reason for this behaviour?
This appears to be a problem with Excel's calculation and significant digits. If you do:
=120.3 - 120 and format the cell to display 15 decimal places, the result appears as:
0.2999999999999970
Here is a brief overview which explains how Excel uses binary arithmetic and that this may result in results divergent from what you would expect:
http://excel.tips.net/T008143_Avoiding_Rounding_Errors_in_Formula_Results.html
You can overcome this by forcing a rounded precision, e.g., to 10 decimal places:
lLines = Int(Round(dRangeUpper, 10) * 100 / lInterval
Kindly use single or double when working with decimals to get more accurate results.
Sub sample()
Dim dRangeUpper As Double
dRangeUpper = CDbl("120.3") - CDbl("120")
lLines = Round(CDbl(dRangeUpper * 100 / 10), 4)
End Sub
output = 3
This is a known Floating point issue within Excel
http://support.microsoft.com/kb/78113
From MSDN:
To minimize any effects of floating point arithmetic storage
inaccuracy, use the Round() function to round numbers to the number of
decimal places that is required by your calculation. For example, if
you are working with currency, you would likely round to 2 decimal
places:
=ROUND(1*(0.5-0.4-0.1),2)
In your case, using round() instead of INT should do the trick using 0 rather than 2