434,807 Members | 1,492 Online
Need help? Post your question and get tips & solutions from a community of 434,807 IT Pros & Developers. It's quick & easy.

Is modulo in VB6 broken or just odd?

 P: 14 -24 mod 7 = -3 The mathematical modulo can't return a value less than 0 according to the professors at my University but the function in Visual Basic 6 does. Is there a fast way around this problem? Feb 3 '08 #1
17 Replies

 Expert 5K+ P: 8,434 Sure - use the Abs() function to get the absolute value, either before or after using Mod(). Feb 3 '08 #2

 P: 14 Did you mean abs(a mod b) or abs(a) mod b? That would reverse it either way. Feb 5 '08 #3

 Expert 5K+ P: 8,434 Did you mean abs(a mod b) or abs(a) mod b? That would reverse it either way. Yeah, that's what I meant by "before or after". As long as it produces the desired result, I don't see that it makes any difference which way you go. Feb 5 '08 #4

 Expert 100+ P: 1,295 Yeah, that's what I meant by "before or after". As long as it produces the desired result, I don't see that it makes any difference which way you go. it doesnt make a difference, but both are wrong -24 mod 7 is 4 because the multiple of 7 below -24 is -28, and -24 -(- 28) is 4. The right way to fix this is if you want (A mod B) and A < 0 then (A *mod* B) = B + (A MOD B) so 4 = 7 + (-24 MOD 7) you can wrap all in ABS to make it will work if B < 0 so use abs( B - (A MOD B)) HTH Note i used MOD for the VB function, and *mod* for the "real" mathematical function. So for an even more general function, you should use Expand|Select|Wrap|Line Numbers if A < 0 then     if B < 0 then C = abs(B- (A MOD B))     if B >= 0 then C = B+ (A MOD B) else     C = A MOD B end if I'll think latter if this can be reduced to a single line. Feb 6 '08 #5

 Expert 100+ P: 1,295 -24 mod 7 = -3 The mathematical modulo can't return a value less than 0 according to the professors at my University but the function in Visual Basic 6 does. Is there a fast way around this problem? What vb function does to get C = A mod B is C = A - fix(A/B) * B when the real definition should be C = A - int(A/B) * B The difference is that INT will give you the integer below a number, FIX will give you the integer part, e.g. FIX(-1.8) = -1 INT(-1.8) = -2 I dont know why VB has the function that way, may be some people rather use it like that. Anyway, instead of using MOD, you can use the definition i've just wrote HTH Feb 6 '08 #6

 Expert 5K+ P: 8,434 -24 mod 7 is 4 Really? Mathematics does some weird things at times. 3 (or perhaps -3) seems much more logical. I dont know why VB has the function that way, may be some people rather use it like that I'd suggest two main possibilities...The people who built VB didn't know it was supposed to work that way. I still say their way seems more intuitive, or at least logical. The Int() function is slightly faster. And perhaps they figured nobody would notice - after all, look how long it's taken. :) Also, they may have spotted the mistake years ago, but couldn't change it without potentially upsetting too much existing code. Wait! What am I thinking - look who we're talking about. As for the general function, I'd be interested to see whether we can crunch it down to a single line (though of course it's not necessary since it would probably be kept in a Public Function somewhere). My first guess is that the SGN() function might come be useful in this regard. Feb 6 '08 #7

 Expert 5K+ P: 8,434 Here are two attempts at a single-line version of the corrected Mod() function. They're straight off the top of my head. I've checked that VB is happy with the syntax, but if either of them actually works that'll be a bonus. Expand|Select|Wrap|Line Numbers Public Sub RealMod(A As Long, B As Long)   RealMod = Abs((B * Abs(A <> B)) + (A Mod B) * Sgn(B))   RealMod = Abs(IIf(A >= 0, A Mod B, IIf(B < 0, B - (A Mod B), B + (A Mod B)))) End Sub To be strictly accurate, the above is not an attempt to produce a corrected Mod() function. It's an attempt to boil down to a single statement the code that Kadghar posted. Whether the two are in fact the same, I'll leave to the mathematicians out there. :) Feb 6 '08 #8

 P: 61 Try this : -24/7 = -3.4286; Round down to nearest integer = -3; now find remainder, 7* -3 = -21 -24 - (-21) = -3 Yup that is correct. No it's not broken, it works perfectly. That is it functions exactly the way the compiler implimented it. Are the Engineers Broken? Yes, The remainder r is supposed to be between zero and the divsor. 0 <= -3 < 7 Feb 6 '08 #9

 Expert 100+ P: 1,295 Try this : -24/7 = -3.4286; Round down to nearest integer = -3; now find remainder, 7* -3 = -21 -24 - (-21) = -3 Yup that is correct. No it's not broken, it works perfectly No, you dont have to round to the nearest integer, you have to use the immediate before integer. check it here: -3 mod 5 = 2 well. its writen as a congruence relation.... But definitions really don't matter, it depends on what you need to do, and know what you are doing in your code and how you use it to achieve a result. Feb 6 '08 #10

 Expert 5K+ P: 8,434 Have you tried my squashed code? I haven't had a chance yet. Feb 6 '08 #11

 P: 61 Think about it terms of distance on a chart -24 is 24 whole units from 0, 7 is 7 whole units from 0; 24 whole units can be split up into how many chunks of 7 whole units, And how many remain? 24 % 7 = 3; [quote]the expression a ≡ b (mod n) (pronounced "a is congruent to b modulo n") means that a − b is a multiple of n.[/qoute] -3 is congruent to 2 ( using modulo 5); means that -3 minus 2 is an even multiple of 5, that is the distance between them is a multiple of 5. And we can see that -3 - 2 = -5, and it is an even multiple of 5. -3 % 5 = -3, not 2 8 % 4 = 0, that is to say that 8 is congruent to zero (using modulo 4) 6 % 5 = 1; 6 is congruent to 1 (using modulo 5) 3 % 5 = 3; 8 % 5 = 3; so 8 is congruent to 3 ( using modulo 5) And actually (using modulo 5 ) there are 5 distinct sets of congruent numbers. the compiler has defined the modulo operator to return the "Remainder" not the set of congruent numbers. so again, for a distance of 24, the reamainder of division by 7 = 3 and since 3 is the distance from 0 to -3 you can safely say that -24 % 7 = -3; Yup it works every time. -24 is congruent to -3 (using modulo 7), and consequently -24 is congruent to 4 ( using modulo 7) So would you say -24 % 7 = 4? No, becuase of the definition of the operator. The distance is from zero even though -24 - ( 4 ) = 28, we are looking for the remainder of deviding the distance from zero not from 4 therfore -24 - ( 0 ) = 24, and indeed the remainder of -24 / 7 is -3 Feb 6 '08 #12

 P: 61 Try this : -24/7 = -3.4286; Round down to nearest integer = -3; actually its -4, rounding down. But we arn't talking about negative or positive #'s anymore, we are talking about direction. and 3 = -3 They if you pardon the pun congruent. No, you dont have to round to the nearest integer, you have to use the immediate before integer. well. its writen as a congruence relation.... and indeed -4 * 7 = -28 ; -24 - ( -28 ) = 4 So we see that 4 is congruent to -3 (using modulo 7) But since 0<= |-28| < |-24| is false 4 cannot be the "remainder". using -2 we find that 7*-2 = -14 ; -24 - (-14) = 10 We see that 10 is congruent to -3 ( using modulo 7) but since 0 <= |10| < |7| is false; 10 cannot be the "remainder". The Correct calculation is -24 % 7 = -3 == 24 % 7 = 3 ( in the negative direction) I hope this helps. Feb 6 '08 #13

 Expert 100+ P: 1,295 ... I hope this helps. Sure it helps, and you do make a point: The vb modulo operator is right in deed. (but ABS won't help it, sorry this time Killer) I thought it was like using a clock, like when you have 20hrs its 8pm, because 20 mod 12 is 8. Same if you have yesterda's 4pm is the same as having today's -8. I think it all depends on how you're using it in your code. e.g. in a countdown, i bet -8 will be more useful. Anyway, if C is A mod B (where B >0): VB will make C = A - fix(A/B) * B. I think the problem is that many (including me, and i assume Dawoodoz's teacher too) would expect it to make C = A - int(A/B) * B (i.e. give you 4pm instead of -8) But as long as you know what you're doing, and you use it to achieve the result you want in your code, i think a definitions discussion is not necesary. Feb 6 '08 #14

 Expert 100+ P: 1,295 Have you tried my squashed code? I haven't had a chance yet. Yes. I just changed it to be a function, and it works great. But i think if it comes to make a function, using the definition will be faster: Expand|Select|Wrap|Line Numbers Public Function RealM(A As Long, B As Long) As Long     B = Abs(B) : RealM = A - Int(A / B) * B End Function ^.^ Feb 6 '08 #15

 Expert 5K+ P: 8,434 If you want faster, you probably should use integer division (\) instead of regular (/). In which case, you might not need the parentheses (not sure). Also, this function should use ByVal for the parameters, so that it doesn't change the variable passed to argument B. Alternatively, you could just define a local variable and use that in place of B. (I think passing by value is the default in .Net versions, isn't it?) Feb 6 '08 #16

 Expert 100+ P: 1,295 ... Also, this function should use ByVal for the parameters, ... I missed it because of my "#\$@"% copy-paste habit. Of course it should be ByVal B as Long. Feb 7 '08 #17

 P: 14 Thanks for the replies. I have a lot to try now. XD Feb 8 '08 #18