Want to protect your cyber security and still get fast solutions? Ask a secure question today.Go Premium

x
  • Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 557
  • Last Modified:

Bug in vb6 comparing int and double

I am going nuts because the following sentence: Int(dCantidadRegistro) = dCantidadRegistro returns false when debugging dCantidadRegistro = 1 so I don't understand anything anymore. The app runs the following code a million times over and over in a thouthand files and each time it fails in a different file so I guess it's some kind of VB bug. I am using VB 6.0 SP6

Dim iindice As Integer
Dim iFreeFile As Integer
Dim dCantidadRegistro As Double
Dim RegistroDJVE2 As RegEntradaDJVE2

Dim LongArchivo As Integer
Dim LongConfArchivo As Integer

iFreeFile = FreeFile

        Open Trim(sArchivo) For Random Lock Read Write As #iFreeFile Len = (Len(RegistroDJVE2))

        LongArchivo = FileLen(sArchivo)
        LongConfArchivo = Len(RegistroDJVE2)
        dCantidadRegistro = FileLen(sArchivo) / Len(RegistroDJVE2)
        'dCantidadRegistro = LongArchivo / LongConfArchivo
       
        'Verify file is not empty
        If (dCantidadRegistro > 0) Then
           
            If (Int(dCantidadRegistro) = dCantidadRegistro) Then
               'Everything is ok so process file
               Call Processfile(RegistroDJVE2, sArchivo, iindice)
            Else
                'Something is wrong with either the file or the structure                
                ShowError "Error de estructura de archivo " & Trim(ArchivoExtension) & " (REG" & LongConfArchivo & "-FILE" & LongArchivo & ")"
           
            End If
   
        Else
           
            'Incrementa variable global de conteo de archivos en blanco
            BlankFiles = BlankFiles + 1
   
        End If

'''''''''''''''''''''''
' Module
'''''''''''''''''''''''
    Public Type RegEntradaDJVE2
        TipoMovimiento As String * 1
        NUMDJVE As String * 16
        Tripli As String * 8
        CANTI As String * 17
        CUMPLIDO As String * 1
        FECTXT As String * 8
        HORTXT As String * 6
        Cliente As String * 5
        CUIT As String * 11
        REFCLI As String * 20
        FECCUM As String * 8
        ADUTRA As String * 3
        NUMDESP As String * 7
        LETDESP As String * 1
        TIPDESP As String * 4
        sFiller As String * 157
        FinLinea As String * 2
    End Type
0
pwebonline
Asked:
pwebonline
  • 8
  • 6
  • 4
  • +3
1 Solution
 
Jaime OlivaresSoftware ArchitectCommented:
you can use mod operator:

if (FileLen(sArchivo) mod Len(RegistroDJVE2) = 0) then
   'etcetera

0
 
pwebonlineAuthor Commented:
Does it make a difference?... I mean, is there any chance mod will fail too?
0
 
pwebonlineAuthor Commented:
Mod fails too. I don't understand the inmed mode shows:
?FileLen(sArchivo)
 275
?Len(RegistroDJVE2)
 275

What is wrong?
0
VIDEO: THE CONCERTO CLOUD FOR HEALTHCARE

Modern healthcare requires a modern cloud. View this brief video to understand how the Concerto Cloud for Healthcare can help your organization.

 
pwebonlineAuthor Commented:
Mod is not good....
?FileLen(sArchivo) mod 1.2
 0
0
 
Jaime OlivaresSoftware ArchitectCommented:
>Mod fails too. I don't understand the inmed mode shows:
>?FileLen(sArchivo)
> 275
>?Len(RegistroDJVE2)
> 275

What is the problem with this?
275 mod 275 must be 0 (meaning exact division). Or maybe you have a different result?

>Mod is not good....
>?FileLen(sArchivo) mod 1.2
> 0
Mod is good for integer divisions, this is not a good example
0
 
pwebonlineAuthor Commented:
I know but the comparition is supposed to verify if the file right or not since the file is written by another application which I don't control. Suppose the file is wrong:
?100 mod 10
 0

?10 mod 1
 0

?275 mod 1
 0
etcetera
0
 
Jaime OlivaresSoftware ArchitectCommented:
mod 1 is the unique exception, you can manage it easily with an If sentence
0
 
Jaime OlivaresSoftware ArchitectCommented:
maybe:

If FileLen(sArchivo) < Len(RegistroDJVE2)

BTW. You don't need to use parenthesis in an If sentence in Visual Basic.
0
 
avi247Commented:
hmm..Interesting. Are you saying that,
say
dCantidadRegistro = 1
Debug.Print Int(dCantidadRegistro) = dCantidadRegistro
returns false????

then thats weird.

you might want to try this approach. look for a decimal place. If its perfectly divisible, double does not have 0
If Instr(dCantidadRegistro,".") = 0 then
----- OK
0
 
pwebonlineAuthor Commented:
I know it's weird....
?dCantidadRegistro
 1
?Int(dCantidadRegistro) = dCantidadRegistro
False
?Int(dCantidadRegistro)
 0
?Instr(dCantidadRegistro,".")
 0

I don't use mod because it's not right... there are a few exceptions besides 1:
?100 mod 10
 0
etcetera

I want to know what's wrong with int(dCantidadRegistro) sometimes when dCantidadRegistro = 1
0
 
Erick37Commented:
Floating point errors are a fact of life in any programming language.

Sometimes the result of a calculation yields a number that is very close to the *right* answer, but is ever so slightly off.

e.g.
0.999999999999998 and 1.000000000000001 both represent the value of 1 in most situations.

Taking Int() of both numbers will result in different values.

Instead of
If (Int(dCantidadRegistro) = dCantidadRegistro) Then
 maybe use:
If (Int(Round(dCantidadRegistro, 4)) = Round(dCantidadRegistro, 4)) Then

Good Luck!
0
 
Erick37Commented:
Also, do not confuse Int() with CInt()

Int() takes the integer portion of the number and discards everything after the decimal.
Int(0.999) = 0
Int(0.55) = 0
Int(1.001) = 1

CInt converts the number to the integer data type.  Rounding up or down as appropriate.
CInt(0.4) = 0
CInt(0.55) = 1
CInt(0.999) = 1
CInt(1.001) = 1
0
 
Mike TomlinsonMiddle School Assistant TeacherCommented:
First of all, this:

    Dim LongArchivo As Integer
    Dim LongConfArchivo As Integer

should be:

    Dim LongArchivo As Long '  <----- Integer isn't very big, and FileLen() returns a Long anyways
    Dim LongConfArchivo As Long ' Again, Integer isn't very big and Len() returns a Long

If your file is good, then LongArchivo will be a multiple of LongConfArchivo.  You can verify that in this way instead:

    Dim quotient As Long
    LongArchivo = FileLen(sArchivo)
    LongConfArchivo = Len(RegistroDJVE2)
    qoutient = LongArchivo \ LongConfArchivo ' <--- Integer Division (Backslash, not Forward Slash)
    If (quotient * LongConfArchivo) = LongArchivo Then
        'Everything is ok so process file
        Call Processfile(RegistroDJVE2, sArchivo, iindice)
    Else
        'Something is wrong with either the file or the structure                
        ShowError "Error de estructura de archivo " & Trim(ArchivoExtension) & " (REG" & LongConfArchivo & "-FILE" & LongArchivo & ")"    
    End If

Regards,

Idle_Mind
0
 
Erick37Commented:
Very good.
0
 
pwebonlineAuthor Commented:
Will it fix the floating point problem? Files just have x number of characters and lines, they don't have 275.000001 characters.
?FileLen(sArchivo)
 275
?Len(RegistroDJVE2)
 275
how come 275 / 275 = floating point when the debugging inmed shows
?LongArchivo / LongConfArchivo
 1

I don't get it
0
 
pwebonlineAuthor Commented:
This is way too weird... I had a stopping point and I swear Int(dCantidadRegistro) = dCantidadRegistro returned false and I left the code stopped for a couple of hours and when I came back it would return true. This is way too weir falks or I'm loosing my mind
0
 
Mike TomlinsonMiddle School Assistant TeacherCommented:
There shouldnl't be any floating point problems wit the code I posted as it uses whole numbers in the calculations.

Idle_Mind
0
 
jimbobmcgeeCommented:
Out of interest (and I don't if it makes a difference) but doesn't FileLen return a length in Bytes, whereas Len returns the number of characters in a string?

If you are comparing a file length in bytes to a string then, if there are any multi-byte characters (as with some non-English character sets), surely the lengths will be different.

Does it make a difference if you use LenB(...) instead of Len(...), as LenB will return the byte length of the string?
0
 
Mike TomlinsonMiddle School Assistant TeacherCommented:
I think you are right jimbobmcgee.  LenB() will account for the padding in Type RegEntradaDJVE2 that will be present in the file but not in memory.

Change:

    LongConfArchivo = Len(RegistroDJVE2)

To:

    LongConfArchivo = LenB(RegistroDJVE2)

Idle_Mind
0
 
Erick37Commented:
Len() is correct.
Len() returns the number of characters, LenB() the number of bytes.
In VB strings, one char = 2 bytes (unicode), in files strings are ascii, one byte per character.



As a side note, reading the documentation on FileLen it says:

"If the specified file is open when the FileLen function is called,
the value returned represents the size of the file immediately before it was opened.
Note   To obtain the length of an open file, use the LOF function."
0
 
Mike TomlinsonMiddle School Assistant TeacherCommented:
I stand corrected.  (Tested with a small random access file)

Thank you Erick37.

Keep it as:
 LongConfArchivo = Len(RegistroDJVE2)

~IM
0
 
jimbobmcgeeCommented:
> Len() returns the number of characters, LenB() the number of bytes.
> In VB strings, one char = 2 bytes (unicode), in files strings are ascii, one byte per character.

Then, for a true indication of file length (including support for Unicode characters), wouldn't the following be a better comparison

    Dim ByteArray() As Byte
    Dim strText As String
    Dim c As Long
    Dim i As Long
   
    strText = "Hello, Jamie"
    ByteArray() = strText

    c = 0
   
    For i = LBound(ByteArray()) To UBound(ByteArray())
   
        Me.Print ByteArray(i); "("; ByteArray(i) > 0; ")";
        If ByteArray(i) > 0 Then c = c + 1
       
    Next i

instead comparing c with FileLen(file), or is Unicode handled differently in file I/O?
0
 
pwebonlineAuthor Commented:
I tried using LOF(iFreeFile):
LongArchivo = LOF(iFreeFile)
LongConfArchivo = Len(RegistroDJVE2)
dCantidadRegistro = (LongArchivo / LongConfArchivo)

LongArchivo = 275 and LongConfArchivo = 275 but dCantidadRegistro = 0,25 but when I go back and run again dCantidadRegistro = (LongArchivo / LongConfArchivo), dCantidadRegistro calculates correctly and returns 1.

Idle_Mind: Your code is ok but it does work for me because it looses it's porpose... I mean this code is supposed to verify if the file I am reading is well written and I do that comparing to the structure so if you make a int division then you will never know if the amount of items are correctly (integer and with no decimals)
0
 
Mike TomlinsonMiddle School Assistant TeacherCommented:
pwebonline,

That is exactly what the my code does!  Let me give you an example.  Suppose you have this definition:

    Public Type myStructure
        strA As String * 10
        strB As String * 10
        strC As String * 10
    End Type

The length of this structure is 30 bytes.  If you wrote one record to the file, it would be 30 bytes long.  If you wrote two records to the file it would be 60 bytes long.  If you wrote three records to the file, it would be 90 bytes long....

So, for a valid file, the length will be a multiple of the length of your structure:

    (Length of File) = (# of records) * (Length of Structure)

Now let's solve this equation for (# of records):

    (# of records) = (Length of File) / (Length of Structure) ' Regular Divison (Forward Slash)

I understand that you already know this.  But..if you change it from regular division to integer division:

    (# of records) = (Length of File) \ (Length of Structure) ' Integer Divison (Backslash)

This will give you the number of WHOLE records in your files.  If 3.14150 records were written, it would return 3.  Now mulltiply the number of whole records in the file by the length of your structure.  If this value matches the actual length of the file then you know you have a valid file.  If they don't match, you know you have a corrupt record or a partial record on the end of the file.

Going back to the example.  Let's suppose you have an invalid file with 3.5 records in it.  This would give you a length of 105 bytes  (For this to be a valid file, it would need 4 records for a length of 120 bytes).  Now consider the code I gave you:

    Dim myStruct As myStructure
    Dim wholeRecords As Long
    Dim fileLength As Long
    Dim structureLength As Long
    Dim validFileLength As Long

    fileLength = FileLen("c:\someFile.txt") ' 105 bytes
    structureLength = Len(myStruct) ' 30 bytes

    ' This will give you the value 3
    wholeRecords = fileLength \ LongConfArchivo ' <--- Integer Division (Backslash, not Forward Slash)
   
    validFileLength = wholeRecords * structureLength ' 90 bytes

    If validFileLength = fileLength  Then ' 90 is not equal to 105

        'Everything is ok so process file

    Else

        'Something is wrong with either the file or the structure                

    End If

Now let's suppose you have a valid file.  What if the file had exactly 3 records in it?  The file length would be 90.  The inumber of whole records returned by the integer division would be 3.  If you multiply the length of the structure (30) by the number of whole records (3), you would get 90.  This matches the actual file length and therefore the file is valid.

I hope I have explained this clearly enough to demonstrate the concept.  If not, I will answer any questions you may have.

Regards,

Idle_Mind
0
 
Mike TomlinsonMiddle School Assistant TeacherCommented:
Sorry, this:

    ' This will give you the value 3
    wholeRecords = fileLength \ LongConfArchivo ' <--- Integer Division (Backslash, not Forward Slash)

should be:

    ' This will give you the value 3
    wholeRecords = fileLength \ structureLength ' <--- Integer Division (Backslash, not Forward Slash)

~IM
0

Featured Post

Become an Android App Developer

Ready to kick start your career in 2018? Learn how to build an Android app in January’s Course of the Month and open the door to new opportunities.

  • 8
  • 6
  • 4
  • +3
Tackle projects and never again get stuck behind a technical roadblock.
Join Now