How do I avoid overflow while using currency?
Hello!
I need to copy a big file (over 2 gb).
I am distributing this work over several activex exes of which each copies a "chunk".
I am having a problem distributing the work over them as I encounter an overflow error, no matter what I try.
I used modulo and int.
Can somebody advise me how to solve this?
Thank you.
Here is my prototype function:
Code:
Private Sub Form_Load()
Dim lCountWorkers&
Dim cBytesToBeCopiedByEach As Currency
Dim cFileSize As Currency
cFileSize = 2247442432#
CalculateNumberOfWorkersAndWork cFileSize, 6, lCountWorkers, cBytesToBeCopiedByEach
End Sub
Public Sub CalculateNumberOfWorkersAndWork(ByVal uFileSize As Currency, ByVal uMaxWorkers As Long, ByRef uCountWorkers As Long, ByRef uBytesToBeCopiedByEach As Currency)
'My code is really crappy. I have tried a lot. This version is just a mockup to show you what I want to do
'I am not even sure if this approach would yield the correct result even if it would not throw the overflow error
uBytesToBeCopiedByEach = uFileSize / uMaxWorkers
Dim wholeParts As Currency
wholeParts = uFileSize \ uMaxWorkers
Dim totalWholePartSize As Currency
totalWholePartSize = wholeParts * uMaxWorkers
If totalWholePartSize = uFileSize Then
uCountWorkers = uMaxWorkers
Else
uCountWorkers = wholeParts + 1
End If
If uFileSize < uMaxWorkers Then
uCountWorkers = uFileSize
uBytesToBeCopiedByEach = 1
End If
End Sub
This one as well throws an overflow error
Re: How do I avoid overflow while using currency?
The \ operator does integer division and works only with "Long" variables. Replace it with "Int(x / y)" to replicate its behavior for numbers larger than "Long".
Re: How do I avoid overflow while using currency?
You can also replace "Mod" with this function that works with larger numbers (including "Decimal"):
Code:
Public Function BigMod(vDividend As Variant, vDivisor As Variant) As Variant
BigMod = vDividend - Int(vDividend / vDivisor) * vDivisor
End Function
Re: How do I avoid overflow while using currency?
Edit: I have now tried RC6, but since I am math noob I have no idea if that is correct:
Code:
Dim lCountWorkers&
Dim cBytesToBeCopiedByEach As RC6.cBigInt
Dim cFileSize As Currency
cFileSize = 2247442432#
Set cBytesToBeCopiedByEach = New_c.BigInt
CalculateNumberOfWorkersAndWork uFileSize, 6, lCountWorkers, cBytesToBeCopiedByEach
Public Sub CalculateNumberOfWorkersAndWork(ByVal uFileSize As Currency, ByVal uMaxWorkers As Long, ByRef uCountWorkers As Long, ByRef uBytesToBeCopiedByEach As cBigInt)
Dim cFileSize As cBigInt
Set cFileSize = New_c.BigInt
cFileSize.InitFromString CStr(uFileSize)
Dim remainingBytes As cBigInt
Set remainingBytes = New_c.BigInt
Set uBytesToBeCopiedByEach = cFileSize.DivInt(uMaxWorkers)
Set remainingBytes = cFileSize.ModInt(uMaxWorkers)
uCountWorkers = uMaxWorkers
Dim s$
s = remainingBytes.ToString
If s <> "0" Then
uCountWorkers = Fix(cFileSize.DivBig(uBytesToBeCopiedByEach))
Dim sMod$
sMod = cFileSize.ModBig(uBytesToBeCopiedByEach).ToString
If sMod <> "0" Then
uCountWorkers = uCountWorkers + 1
End If
End If
If cFileSize.CompInt(uMaxWorkers) < 0 Then
uCountWorkers = cFileSize.ToString
uBytesToBeCopiedByEach.InitFromString "0"
End If
End Sub
Re: How do I avoid overflow while using currency?
Yeah, math with any kind of "integer" can get a bit tricky and confusing.
Here is some code that hopefully clears a bit of it up:
Code:
Option Explicit
Private Sub Form_Load()
Dim c1 As Currency
Dim c2 As Currency
c1 = 5
c2 = 6
Debug.Print TypeName(c1 \ c2) ' Reports "Long"
Debug.Print TypeName(c1 / c2) ' Reports "Double"
Debug.Print TypeName(c1 Mod c2) ' Reports "Long"
' So, how do we divide these currencies?
' One "safe" way is to:
Debug.Print TypeName(CDec(c1) / CDec(c2)) ' Reports "Decimal"
' Since a "Decimal" type completely covers the range of a Currency,
' it's safe to go:
Dim c3 As Currency
c3 = CDec(c1) / CDec(c2)
End Sub
If you truly want a MOD for Currency, that's a bit of different problem, and I don't believe VanGogh's approach will work for all possible values of Currency.
@VanGogh, I didn't test, but what if vDividend is near the max of a Currency, and vDivisor = 0.0001? That internal division should fail. Doing a MOD on floating point numbers is a bit unusual, but not unheard of. (One place I frequently use it is when dealing with degrees, or radians).
Re: How do I avoid overflow while using currency?
A simple (although possibly not the speediest) way to do a Currency MOD is something like the following:
Code:
Public Function CurMod(c1 As Currency, c2 As Currency) As Currency
CurMod = c1
Do While CurMod > c2: CurMod = CurMod - c2: Loop
End Function
And this won't overflow (unless it's truly overflowing the Currency type, such as a huge negative C2).
Re: How do I avoid overflow while using currency?
if you dont mind using a c dll you can use unsigned types including 64 bit numbers and math operations w/ overflow wrapping
http://sandsprite.com/tools.php?id=31
Re: How do I avoid overflow while using currency?
The very definition of a remainder (MOD) implies integer operands. The function takes variant parameters especially to accommodate the biggest possible integers (Decimal type). Other than that I don't know what else can you ask of it.
Re: How do I avoid overflow while using currency?
Code:
Option Explicit
Private Declare Function RtlLargeIntegerDivide Lib "ntdll" ( _
ByVal cA As Currency, _
ByVal cB As Currency, _
Optional ByRef cR As Currency) As Currency
Private Sub Form_Load()
Dim cRemainder As Currency
' // Currency is int64 / 10000
' // Calc 1234123424124 / 100 = 12341234241
Debug.Print RtlLargeIntegerDivide(123412342.4124@, 0.01@) ' // 1234123,4241 [ok]
' // Calc 1234123424124 mod 100 = 24
RtlLargeIntegerDivide 123412342.4124@, 0.01@, cRemainder ' // 0,0024 [ok]
Debug.Print cRemainder
End Sub
Re: How do I avoid overflow while using currency?
AI (Gemini):
Quote:
Can a MOD operator be performed on floating point numbers?
Yes, the MOD operator can be performed on floating-point numbers.
While it's primarily used for integers to find the remainder after division, many programming languages extend its functionality to floating-point numbers. The result is the remainder of the floating-point division.
That's pretty much exactly the gist of what I originally said.