VBA Modulo Operation on large decimal numbers [duplicate] - excel

This question already has answers here:
handling big number in vba
(2 answers)
Closed last month.
i am trying to calculate: A random number in the range 10^25 mod a random number in the range of 100.
I saved the first random number as a Variant because the number is too big to be saved as an Integer.
The result of the solution should be something between 1 and 100, so it could be saved as an Integer.
My idea is to break down the numbers into smaller numbers (prim factorisation) and calculate the modulo on smaller numbers, so we don't need to calculate in the range of 10^25.
For example calculation:
300400000717120000131495 mod 97 = 1
How to calc this by using VBA.
Thank you in advance.
Fabian

Does this work for you?
Sub test_this()
Debug.Print find_modulus("300400000717120000131495", 97)
End Sub
Function find_modulus(large_number As String, divisor As Long)
Dim quotient As Variant, integer_quotient As Variant
quotient = CDec(large_number)
integer_quotient = Int(quotient / divisor) * divisor
find_modulus = quotient - integer_quotient
End Function
(Variable names changed to make more sense.)

Related

Mod calculation in VBA

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

VBA function for Upside/Downside Capture

apologies for my ignorance, I'm brand new to VBA - I'm sure this is a simple problem...
I'm trying to write a fn. for up/down side capture in VBA. This is the problem:
There are two columns. One has fund performance in % (I've labelled 'returns'). The other has index performance in % (labelled 'index'). Both are same length / same number of rows. I need both to be variables to enter to the fn.
For UpsideCapture fn., for all nos. in the index column >0, I want to find the corresponding number in the returns column (which will be on the same row). Once I have those numbers I can compound them.
I've tried using Offset, assuming the returns column is 15 columns to the left of the index column but it doesn't return anything, and I don't really want to rely on it always being 15 columns apart (it arbitrary).
Many thanks!
One of my rubbish attempts is below. Any help is much appreciated. Its really just a case of finding the correct corresponding row based on the value in the index column...
Function UpsideCapture(returns As Range, index As Range) As Variant
Dim n As Integer
Dim m As Integer
Dim i As Integer
n = returns.Rows.Count
m = index.Rows.Count
For i = 1 To m
If index(i) > 0 Then
Upsidecap = ((1 + Upsidecap) * (1 + Offset(returns(i), -15))) - 1
End If
Next
UpsideCapture = Upsidecap
End Function
example

How to round a list of decimals in Excel, so that the sum of the whole numbers equal a defined total?

Having difficulty developing an excel function that will round a list of decimals, so that the sum of the whole numbers equals the original or a defined total.
Edit
I guess one way to do it is writing a function that first searches for the largest numbers and rounds them to the nearest whole number. That whole number is then counted and the function moves on to the next, until the total count equals the target total.
The problem that I am running into is that if there are too many numbers that are closer to 0, then the function will never equal the target total. So what the function then needs to do is identify the largest decimals, round them up, count, and then move on to the next until the sum of the count is equal to the target total. The left over data can then round to 0.
Sorry, I hope this is clearer....
I am dealing with larger data sets where the totals of the rounded whole numbers have much larger deviations to the original total.
It would preferable if this could be accomplished with an excel function, otherwise I am also open to doing in VBA.
Thanks!
Edit 3: Here is an example data set:
Please study my project VBA.Round.
Browse to paragraph Rounding a series of numbers to a sum
Code is way too much to post here, but an example workbook is included for download.
Example:
This function will read the range of distribution values, round the sum, and fill the two ranges with rounded values of 2 and zero decimals, totalling to the requested total (confirmed, as seen, by the formula):
' Practical example for using Excel ranges for RoundSum
'
' Source URL:
' https://stackoverflow.com/questions/63715043/how-to-round-a-list-of-decimals-in-excel-so-that-the-sum-of-the-whole-numbers-e
'
' 2020-09-14. Gustav Brock, Cactus Data ApS, CPH.
'
Public Sub RoundDistribution()
' Named ranges. These should pairwise match in row size.
Const VolumeName As String = "Volume"
Const PercentValuesName As String = "Percent_Distribution"
Const ValuesName As String = "Distribution"
Const RoundedValuesName As String = "Rounded_Distribution"
Dim Range As Excel.Range
Dim Values() As Currency
Dim Results() As Currency
Dim Total As Integer
Dim Index As Integer
' Read percent distribution values from the named range.
Set Range = ThisWorkbook.Names(PercentValuesName).RefersToRange
' Read original volume value.
Total = ThisWorkbook.Names(VolumeName).RefersToRange(1, 1)
' Dim input and output arrays.
ReDim Values(1 To Range.Rows.Count)
ReDim Results(1 To Range.Rows.Count)
' Fill input array.
For Index = LBound(Values) To UBound(Values)
Values(Index) = Range(Index, 1)
Next
' Round total and retrieve array with distribution values.
Results = RoundSum(Values, RoundMid(Total), 2)
' Fill named range with distribution values.
For Index = LBound(Results) To UBound(Results)
ThisWorkbook.Names(ValuesName).RefersToRange(Index, 1) = Results(Index)
Next
' Round total and retrieve array with rounded distribution values.
Results = RoundSum(Values, RoundMid(Total))
' Fill named range with rounded distribution values.
For Index = LBound(Results) To UBound(Results)
ThisWorkbook.Names(RoundedValuesName).RefersToRange(Index, 1) = Results(Index)
Next
End Sub
Output:
Note please, that the function is capable of rounding to any number of decimals, and to select one instance only of the values 0.34 to obtain a match.
The full demo (Excel workbook) and code is still for download on GitHub.
I'd agree with #pghcpa this is rather an arithmetic problem.
One idea for solution:
order the numbers descending on their fraction part
take the floor of each (i.e ignoring the fractions)
take the sum of those floors
compare that sum to the desired sum, take the difference
This way you'd probably have a positive difference, so you can start from the top and add 1 to each number downwards, all until the difference is gone.

New to VBA in Excel. Trying to sum an incremented function

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.

Excel VBA Function Fails but Formula works in sheet

Weird Math Error in VBA for Excel
Hi all, would love feedback on unsusual error I'm getting.
Very strange. I have a simple formula that works great if I
only use it in a normal sheet cell and copy it down by columns,
but if I try to do a simple iteration in vba code to perform the same function I get the wrong values.
Description : A number is squared, then divided by another value
between 0.99 to 1.99, next the modulus is taken and then
the number is squared again and the whole formula repeated.
If I copy the formula statement down column wise it calcs fine,
including reasonable decimal accuracy.
There are four inputs ;
base value (inputx)
decx = divisor
mod value
The first formula placed at (E2) looks like ; =MOD(((B2^2)/$B$3),$B$4)
In (E3) this statement is placed ; =MOD(((E2^2)/$B$3),$B$4)
Then this exact same statement is copied down, columnwise to the next 98 cells.
All great, no problem. It seems accurate value wise, right to decimal
precision, with values past the decimal point showing in all column cells.
Some sample input values for testing ;
INPUTX --> 231
DECX 1.010101
MOD 400
LOOPTIMES 100
But when I try to implement this is Excel VBA code (Excel 2007)
I often get the wrong values and absolutely no values past the decimal point ever show.
Have tried using all kinds of different data types ; single, double, variant, etc... but all values returned by the VBA function I made always returns
whole numbers, and is often wrong and certainly does not agree with the
values returned by the simple column based statements.
Have tried to find ways around this or to fix this, came across "CDEC", tried
this and nothing changed. Totally stumped and would love some insight into
if this can be fixed so that the function loop returns the same values with
same kind of decimal precision as the column based statements and
would greatly appreciate feedback on how mthis can be done.
Am including my sample code below ;
Public Function SQRD(inputx As Variant, looptime As Variant, decx As Variant) As Variant
Application.Volatile
Dim Count As Integer
SQRD = CDec(inputx)
'Dim decx As variant
Count = 1
For Count = 1 To looptime
SQRD = CDec(SQRD ^ 2) '+ looptime
SQRD = CDec(SQRD Mod 400 / decx)
Next Count
End Function
I will only address your use of the VBA Mod operator. It is NOT equivalent to the Excel MOD function. In particular, the VBA Mod operator will round floating point numbers to integers before performing the operation.
To use a VBA function that mimics the Excel MOD function, use something like:
Function xlMOD(a As Double, b As Double) As Double
xlMOD = a - (b * (a \ b))
End Function
EDIT
There seems to be a bug in VBA (or a documentation error). In the formula above, the \ operator is supposed to be the integer division operator. It does return an integer result. However, it does not truncate, rather it rounds. Actually, what it may be doing, is performing VBA type rounding on the number and divisor, before returning the result.
Therefore, a proper vba function to mimic the Excel MOD function would be:
Function xlMOD(a As Double, b As Double) As Double
xlMOD = a - Int(a / b) * b
End Function
Lots amiss with your code. No need for looping as far as I can see, and you're dividing after the mod not before
This seems to do the trick
Public Function NuFunc(InputX As Variant, DecX As Variant) As Variant
NuFunc = ((InputX ^ 2) / DecX) Mod 400
End Function

Resources