Mod com Duplas
Estou fazendo algo errado ou o operador VBA Mod na verdade não funciona com valores de ponto flutuante como Doubles?
Então, eu sempre achei que o operador VBA Mod funcionaria com o Doubles com base noDocumentação VB, mas, ao tentar descobrir por que minha função de arredondamento não funciona, encontrei um comportamento inesperado do Mod.
Aqui está o meu código:
Public Function RoundUp(num As Double, Optional nearest As Double = 1)
RoundUp = ((num \ nearest) - ((num Mod nearest) > 0)) * nearest
End Function
RoundUp(12.34)
retorna12
ao invés de13
então eu cavei um pouco mais fundo e descobri que:
12.5 Mod 1
retorna0
com o tipo de retorno Long, enquanto eu esperava 0,5 com um tipo de Double.
Conclusão
Como@ ckuhn203 aponta em sua resposta, de acordo com a especificação VBA,
O operador de módulo ou restante divide o número1 pelo número2 (arredondando números de ponto flutuante para números inteiros) e retorna apenas o restante como resultado.
E
Normalmente, o tipo de dado do resultado é um Byte, Variante de byte, Inteiro, Variante de número inteiro, Longo ou Variante contendo um Longo, independentemente de o resultado ser ou não um número inteiro. Qualquer parte fracionária é truncada.
Para meus propósitos, preciso de um módulo de ponto flutuante e, por isso, decidi usar o seguinte:
Public Function FMod(a As Double, b As Double) As Double
FMod = a - Fix(a / b) * b
'http://en.wikipedia.org/wiki/Machine_epsilon
'Unfortunately, this function can only be accurate when `a / b` is outside [-2.22E-16,+2.22E-16]
'Without this correction, FMod(.66, .06) = 5.55111512312578E-17 when it should be 0
If FMod >= -2 ^ -52 And FMod <= 2 ^ -52 Then '+/- 2.22E-16
FMod = 0
End If
End Function
aqui estão alguns exemplos:
FMod(12.5, 1) = 0.5
FMod(5.3, 2) = 1.3
FMod(18.5, 4.2) = 1.7
Usar isso na minha função de arredondamento resolve meu problema específico.