Logo_Access_global_380x114Favicon_Access_global_180x180Logo_Access_global_380x114Logo_Access_global_380x114
  • Home
  • University
    • Destellos formativos
  • Labs
  • TV
  • Secciones
    • El mundo de Access
    • Explorando VBA
      • Artículos sobre VBA
      • Un trocito de código
    • Entrevistas
      • Profesionales de Access
    • El rincón de Excel
    • Bases de datos
      • MS SQL
      • MySQL
      • postgreSQL
      • SQLite
    • Clases magistrales
    • Utilidades hechas con Access
  • Access en el mundo
  • ¿Quiénes somos?
  • Cómo colaborar
  • Eventos
✕
            No hay resultados Mostrar todos los resultados
            mcFileDialog Cuadro de diálogo Abrir archivo
            28/11/2021
            Evento
            Dim WithEvents
            13/12/2021
            Mostrar todos

            Tipo de variable Decimal

            Publicado por José Bengoechea
            Categorías
            • Artículos sobre VBA
            Etiquetas
            • Decimal
            • Jose Bengoechea
            • Módulo de clase
            • VB_UserMemId

            Problemas de precisión con las variables de coma flotante

            Las variables de coma flotante (Double y Single) tarde o temprano van a dar problemas de redondeo o de comparación. Es posible que nunca te haya tocado, o que nunca te hayas fijado, pero prueba lo siguiente:

            ¿Te has fijado en los resultados?

            Cuando escribimos números en el editor de VB, el tipo predeterminado es Double y es la falta de precisión de estos números de coma flotante el origen del problema.

            Las variables de tipo Currency lo solucionan, pero sólo si no necesitas más de cuatro decimales; sin embargo, en ocasiones, necesitamos más; por ejemplo, la norma de Facturae dice que el valor del producto puede tener hasta 8 decimales.

            El tipo de datos Decimal

            No existe una variable tipo Decimal, pero existe un subtipo del tipo Variant que es Decimal. Además, tenemos el tipo de datos Decimal, que puede almacenar en una tabla valores de precisión Decimal.

            La forma de que una variable Variant se convierta al subtipo Decimal es adquiriendo un valor que ya es Decimal (por ejemplo, al leerlo de la tabla), o convirtiéndola a Decimal usando la función cDec().

            Es decir, si queremos usar algo equivalente a una variable Decimal, es decir un Variant de subtipo Decimal, primero debemos dimensionarla como Variant y luego transformarla con cDec():


            Una clase como un tipo de variable

            A mí me gustaría disponer de un tipo de variable como el que se define en el xsd de Facturae, DoubleUpToEightDecimalType, o sea Decimal y hasta 8 decimales y, como no existe, me lo invento.

            De momento, creo una clase que se limita a hacer la conversión con cDec y guardar el valor en una variable Variant privada:

            Option Compare Database
            Option Explicit
            Private v_Value As Variant
            
            Public Property Get Value() As Variant
               Value = (v_Value)
            End Property
            
            Public Property Let Value(ByVal NewValue As Variant)
               If Not IsNumeric(NewValue) Then
                  Err.Raise 104, , "No coinciden los tipos. Sólo se admiten valores numéricos"
               Else
                  v_Value = CDec(NewValue)
               End If
            End Property

            Pero también me gustaría que redondeara a 8 decimales si es que tiene más.

            La única función que redondea correctamente en Access, evitando el redondeo bancario, es Format(). Si tenías alguna función personalizada que use Int(), ya has visto en los ejemplos de más arriba lo que te puede ocurrir.

            Basta con cambiar una línea, y nos queda así:

            Option Compare Database
            Option Explicit
            Private v_Value As Variant
            
            Public Property Get Value() As Variant
               Value = (v_Value)
            End Property
            
            Public Property Let Value(ByVal NewValue As Variant)
               If Not IsNumeric(NewValue) Then
                  Err.Raise 104, , "No coinciden los tipos. Sólo se admiten valores numéricos"
               Else
                  v_Value = CDec(Format(NewValue, "0.00000000"))
               End If
             
            End Property

            Todavía no está a mi gusto. Empezamos con que para dimensionar la variable tenemos que usar New, cosa que no ocurre con las variables de verdad, y, además tenemos que usar Value para asignarle u obtener el valor.

            Con lo de New nos tendremos que quedar, pero podemos evitar la molestia de tener que usar Value para todo.

            Especificar el miembro predeterminado de una clase

            Cuando en VBA nos referimos, por ejemplo, al valor de un cuadro de texto de un formulario, no necesitamos especificar la propiedad Value del mismo, pues sabemos que Value es la propiedad predeterminada. Lo mismo podemos hacer en nuestras propias clases y definir cuál es su propiedad predeterminada.

            Para ello debemos añadir el atributo VB_UserMemId = 0 en el Property Get del miembro que queremos que sea el predeterminado de la clase, en este caso Value. Es importante que lo escribamos en la línea inmediatamente después de la de Public Property Get, pues si dejamos una línea en blanco no va a funcionar.

            Es algo que no podemos hacer directamente en VBE, pues ese atributo, aunque exista, no será visible. Debemos exportar el módulo de clase, editarlo con un editor de texto y volver a importarlo:

            Si te fijas, en el archivo de texto que hemos importado existen otros Attribute que no se ven en el editor de VB. Busca en internet acerca de ellos. Son interesantes.

            Probar la clase

            Después de importar de nuevo el archivo .cls, nuestro módulo de clase se comportará casi como un tipo de variable.

            Eso sí, debemos tener en cuenta que el subtipo Decimal es un tipo que ocupa en memoria el doble que otro tipo de datos numérico, lo que le hace lento en cálculos masivos; si, además, cada vez que se le invoca, estamos ejecutando código y convirtiendo variables, el cálculo será mucho más lento. Sin embargo, en la mayoría de los usos de gestión, por ejemplo, generar una Factura Electrónica, esa lentitud será completamente imperceptible.

            También debemos tener en cuenta que, puesto que los números que escribamos en el editor de VBE son Double, puede haber valores con muchos decimales que no podemos escribir directamente en el editor, pues los trunca o los transforma. En su lugar debemos escribir el valor como cadena de texto; al ser un Variant, no hay problema en meter un texto y, como luego lo convierte con cDec(), al final tenemos un subtipo decimal.


            Compartir
            0
            José Bengoechea
            José Bengoechea

            Entradas relacionadas

            15/01/2022

            El evento NotInList


            Leer más
            Evento
            13/12/2021

            Dim WithEvents


            Leer más

            Deja una respuesta Cancelar la respuesta

            Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

            ETIQUETAS

            Access API BD Botones ComboBox Consultas CountOfLines CStr Diseño DoCmd Excel Exportar Fecha FileSystemObject Filtros For Each...Next Formulario Formularios Funciones Funciones de dominio GetFolder GetWindowRect Google maps Informes InStr Kill Left Listbox Mid Módulos Node ProcCountLines Procedimientos ProcOfLine References Replace Ribbon RunCommand Seguridad Split SysCmd Tablas TreeView VBA VBIDE

            ÚLTIMAS ENTRADAS

            • 0
              Tratamiento de errores: otras herramientas útiles
              31/03/2023
            • 0
              Tratamiento de errores: compilación condicional
              30/03/2023

            ¿QUIERES PUBLICITAR TU EMPRESA AQUÍ?

            SUSCRÍBETE A NUESTRO
            NEWSLETTER

            Recibirás información puntual sobre el mundo de Access y VBA

            ¡Próximamente!

            Promovemos el uso de Access y de la programación en VBA en todo el mundo

            Centro de conocimiento


            Toda la sabiduría de los mejores programadores de Access y VBA a tu alcance.

            Legal

            Política de privacidad

            Condiciones de uso

            Condiciones del redactor

            ®Access Global 2021 | All right reserved
                      No hay resultados Mostrar todos los resultados