Page 1 of 1

Encode Base16

Posted: Fri Jan 25, 2019 6:36 pm
by RSalazarU
Amigos del foro:

En bolivia se esta empezando a implementar un nuevo de sistema de facturacion (como en otros paises).

Uno de los pasos para el envio de la informacion es la codificacion de un numero a Base16.
Por lo que entiendo codificar a Base16 es pasar un numero a hexadecimal
El problema es que el numero es demasiado largo (52 digitos)

Ejemplo:
Este numero (resultado de la conctenacion de otros numeros) debo codificarlo a Base16
-> 0001234567890201811151310009990000101010000000100005

El resultado debe ser (segun el ejemplo que ponen):
-> D83FF05798D81FFC7426DE08E0C6F3C79884A6A5

Utilizando la funcion de xharbour: NumToHex( <nNum>|<pPointer>, [<nLen>]) el programa se cierra sin dar nungun mensaje
? NumToHex(0001234567890201811151310009990000101010000000100005)

Del internet descargue esta funcion:

Code: Select all

//----------------------------------------------------------------------------//
// Retorna a String da Base dada (2 a 36) correspondente
// ao número decimal dado
//----------------------------------------------------------------------------//
function DecToBase(Base, Dado)
    Local Valor, NumDig, Digs, Div, IDiv, Saida, i

    Valor := Dado
    Digs := "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"

    NumDig := 0
    while (Valor >= 1)
        Valor := Valor / Base
        NumDig := NumDig + 1
    end

    Valor := Dado
    Saida := ""
    if NumDig = 0 //then
       NumDig := 1
    endif
    for i := NumDig - 1 to 0 step -1
        Div := Base ^ i
        IDiv := Int(Valor / Div)
        Saida := Saida + Substr(Digs, IDiv + 1, 1)
        Valor := Valor - Div * IDiv
    next
    //DecToBase = Saida
Return Saida
pero solo sirve para numeros pequeños

Alguien sabe como hacer el Encode Base16

De antemano, muchas gracias por la ayuda

Rolando
Cochabamba, Bolivia

Re: Encode Base16

Posted: Fri Jan 25, 2019 7:48 pm
by RSalazarU
Buscando en el internet, lei que debo usar una libreria para manejo de numeros largos/grandes.
Alguien sabe que libreria para manejar numeros largos/grandes

Gracias de antemano

Re: Encode Base16

Posted: Sat Jan 26, 2019 2:17 pm
by RSalazarU
Alguna sugerencia??

Lo que necesito, basicamente, es convertir un numero GRANDE de DECIMAL a HEXADECIMAL :

Ejemplo:
DE: 0001234567890201811151310009990000101010000000100005
A: D83FF05798D81FFC7426DE08E0C6F3C79884A6A5

Lo que aconsejan, en el internet, es: primero llevar e DECIMAL a BINARIO y luego a HEXADECIMAL
Para esto existen dos metodos (DECIMAL a BINARIO):
1. Division sucesiva por dos
Problema: al dividir un numero grande por 2 el programa se cierra
2. Resta y potencias descendentes de dos
Problema: al calcular la potencia de 2 mayor al numero grande el programa se cierra

Cualquier ayuda se las agradecere infinitamente

Rolando

Re: Encode Base16

Posted: Sat Jan 26, 2019 10:05 pm
by Baxajaun
Rolando,

has utilizado la función StrToHex()

Saludos

Re: Encode Base16

Posted: Tue Jan 29, 2019 10:20 am
by Baxajaun
Rolando,

utilizando la función de Harbour DecToHexa() de la librería hbmisc he llegado a
Image

Puedes poner el enlace en el que la cadena 0001234567890201811151310009990000101010000000100005 se debe convertir a D83FF05798D81FFC7426DE08E0C6F3C79884A6A5
?

Muchas gracias.

Saludos

Re: Encode Base16

Posted: Tue Jan 29, 2019 5:32 pm
by karinha

Re: Encode Base16

Posted: Wed Jan 30, 2019 11:11 pm
by RSalazarU
Baxajaun:

En este enlace hacen la conversion:
https://www.mathsisfun.com/binary-decim ... erter.html

Y avanzando mas en el tema, te comento que en java existe una clase llamada BigInteger() que hace la conversion facilmente
https://docs.oracle.com/javase/7/docs/a ... teger.html

Asi me puse a crear una:

Code: Select all

CLASS TBigInteger //FROM TGeneric

   DATA cNumero

   METHOD New( )                     CONSTRUCTOR

   METHOD Add()
   METHOD Suma2()
   METHOD SumaN()

   METHOD Subtract()
   METHOD Resta2()
   METHOD RestaN()

   METHOD Multiply()
   METHOD Multiplica2()
   METHOD MultiplicaN()

   METHOD Divide() VIRTUAL

   METHOD Potencia()
   METHOD PotenciaN()

   METHOD ToHex()

ENDCLASS

//------------------------------------------------//
METHOD New( cNumero ) CLASS TBigInteger
   ::cNumero := cValToChar(cNumero)
return Self

//------------------------------------------------//
METHOD Add( cNumero ) CLASS TBigInteger
   ::cNumero := ::SumaN({::cNumero, cNumero})
Return ::cNumero
//------------------------------------------------//
METHOD Suma2( cNumero1, cNumero2 ) CLASS TBigInteger
return ::SumaN({cNumero1, cNumero2})
//------------------------------------------------//
METHOD SumaN( aNumeros ) CLASS TBigInteger
    Local n
    Local m
    Local k
    Local i
    Local cRes
    Local cResto
    Local cTotal

    n := Len(aNumeros)

    For k := 1 To n
        aNumeros[k] = RTrim(aNumeros[k])
    Next

    // m será el número de mayor longitud
    m := 0
    For k := 1 To n
        If Len(aNumeros[k]) > m
       m = Len(aNumeros[k])
    Endif
    Next

    For k := 1 To n
        aNumeros[k] = PadL(aNumeros[k], m, " ")
    Next

    // sumar las filas obtenidas
    cRes = ""
    cResto = "0"
    cTotal = ""
    For k := m To 1 Step -1
        cRes = cResto
        For i = 1 To n
            cRes = cValToChar(Val(cRes) + Val(/*"0" + */SubStr(aNumeros[i], k, 1)))
        Next
        cTotal = Right(cRes, 1) + cTotal
        If Len(cRes) - 1 < 1
            cResto = "0"
        Else
            cResto = Left(cRes, Len(cRes) - 1)
        End
    Next

  //If cResto <> "0"
    If !(cResto == "0")
       cTotal = cResto + cTotal
    End

    cTotal := StrTran(LTrim(StrTran(cTotal,"0"," "))," ","0")
Return cTotal


//------------------------------------------------//
METHOD Subtract( cNumero ) CLASS TBigInteger
   ::cNumero := ::Resta2( ::cNumero, cNumero )
Return ::cNumero
//------------------------------------------------//
METHOD Resta2( cNumero1, cNumero2 ) CLASS TBigInteger
    Local k
    Local m
    local cSigno
    Local cRes
    Local cResto
    Local cPresto
    Local cTotal

    //quitamos ceros por delante y espacios de atras
    cNumero1 := StrTran(LTrim(StrTran(RTrim(cNumero1),"0"," "))," ","0")
    cNumero2 := StrTran(LTrim(StrTran(RTrim(cNumero2),"0"," "))," ","0")

    m := Len(cNumero1)
    If Len(cNumero1) < Len(cNumero2)
    m := Len(cNumero2)
        cNumero1 = PadL(cNumero1, m, " ")
    elseIf Len(cNumero2) < Len(cNumero1)
        cNumero2 = PadL(cNumero2, m, " ")
    endif

    // Poner el mayor(más largo) como primer número
    cSigno := ""
    if cNumero1 < cNumero2 //comparacion de strings: valido siempre y cuando los string sean del mismo tamaño
       cSigno := "-"
       swap(@cNumero1,@cNumero2)
    endif

    // cRestar las filas obtenidas
    cRes = ""
    cResto = "0"
    cPresto = "0"
    cTotal = ""

    For k := m To 1 Step -1
        cRes = cValToChar(Val(/*"0" + */SubStr(cNumero1, k, 1)) - Val(cPresto) - (Val(/*"0" + */SubStr(cNumero2, k, 1)) + Val(cResto)))

    If Val(cRes) < 0
            cRes = cValToChar(Val(cRes) + 10)
        cPresto = "1"
        else
        cPresto = "0"
        End

    cTotal = Right(cRes, 1) + cTotal

        If Len(cRes) - 1 < 1
            cResto = "0"
        Else
            cResto = Left(cRes, Len(cRes) - 1)
        End
    Next

  //If cResto <> "0"
    If !(cResto == "0")
        cTotal = cResto + cTotal
    End

    cTotal := StrTran(LTrim(StrTran(cTotal,"0"," "))," ","0")
Return cSigno + cTotal
//------------------------------------------------//
METHOD RestaN( aNumeros ) CLASS TBigInteger
    Local i
    Local cTotal

    cTotal = aNumeros
    For i = 2 To Len(aNumeros)
        cTotal = ::Resta2(cTotal, aNumeros[i])
    Next
Return cTotal


//------------------------------------------------//
METHOD Multiply( cNumero ) CLASS TBigInteger
   ::cNumero := ::Multiplica2( ::cNumero, cNumero )
Return ::cNumero
//------------------------------------------------//
METHOD Multiplica2( cNumero1, cNumero2) CLASS TBigInteger
    Local n
    Local i
    Local k
    Local j
    Local c1
    Local c2
    Local cResto
    Local cRes
    local aNumeros

    //quitamos ceros por delante y espacios de atras
    cNumero1 := StrTran(LTrim(StrTran(RTrim(cNumero1),"0"," "))," ","0")
    cNumero2 := StrTran(LTrim(StrTran(RTrim(cNumero2),"0"," "))," ","0")

    // Poner el más largo como primer número
    If Len(cNumero2) > Len(cNumero1)
        swap(@cNumero1, @cNumero2)
    End

    // El número de operaciones necesarias
    // será la cantidaNumeros de cifras del más pequeño
    aNumeros:=Array(Len(cNumero2))//ReDim aNumeros(Len(cNumero2) - 1)
    n = 0
    cResto = "0"
    cRes = ""

    // Multiplicar formando filas con los cResultaNumerosos (al estilo manual)
    For i := Len(cNumero2) To 1 Step -1
        n = n + 1
        aNumeros[n] = ""

        // AñaNumerosir espacios(ceros) a la derecha según la cifra (fila) que se procese
        For k = 2 To n
            aNumeros[n] = aNumeros[n] + "0"
        Next
        c1 = substr(cNumero2, i, 1)

        // Para simplificar las cosas
        // se comprueba si se multiplicará por cero o por uno
        // de forma que no sea necesario hacer estas operaciones
        If c1 = "0"
            aNumeros[n] = Replicate("0", Len(cNumero1)) + aNumeros[n]
        ElseIf c1 = "1"
            aNumeros[n] = cNumero1 + aNumeros[n]
        Else
            For j := Len(cNumero1) To 1 Step -1
                c2 = Substr(cNumero1, j, 1)

        cRes = cValToChar(Val(/*"0" +*/ c1) * Val(/*"0" +*/ c2) + Val(cResto))

                aNumeros[n] = Right(cRes, 1) + aNumeros[n]

              //If Len(cRes) - 1 < 1
                If Len(cRes) = 1
                    cResto = "0"
                Else
                    cResto = Left(cRes, Len(cRes) - 1)
                End

            Next
            If cResto <> "0"
               aNumeros[n] = cResto + aNumeros[n]
               cResto = "0"
            End
        End
    Next
Return ::SumaN( aNumeros )
//------------------------------------------------//
METHOD MultiplicaN( aNumeros ) CLASS TBigInteger
    Local i
    Local cTotal

    cTotal = aNumeros[1]
    For i = 2 To Len(aNumeros)
        cTotal = ::Multiplica2(cTotal, aNumeros[i])
    Next
Return cTotal

//------------------------------------------------//
METHOD Potencia( cElevado ) CLASS TBigInteger
   ::cNumero := ::PotenciaN( ::cNumero, cElevado )
Return ::cNumero
//------------------------------------------------//
METHOD PotenciaN(cNumero , cElevado ) CLASS TBigInteger
    Local n
    Local k
    Local aNumeros
    local cResultado

    do case
    case Val(cElevado)=0
       cResultado := "1"
    case Val(cElevado)=1
       cResultado := cNumero
    otherwise
       n := Val(cElevado)
       aNumeros := Array(n)
       For k = 1 To n
           aNumeros[k] = cNumero
       Next
       cResultado := ::MultiplicaN( aNumeros )
   endcase
Return cResultado

//------------------------------------------------//
METHOD ToHex( ) CLASS TBigInteger
   local i
   local cPotencias2
   local cResto
   local cBin

   ::cNumero := StrTran(LTrim(StrTran(RTrim(::cNumero),"0"," "))," ","0")

   cPotencias2 := PadL("",Len(::cNumero))
   i:=0
   Do While cPotencias2 < ::cNumero
      cPotencias2 := Padl(::PotenciaN("2",cValToChar(i)),len(::cNumero))
      i++
   enddo

   i -= 2
   cResto := ::Resta2(::cNumero, ::PotenciaN("2",cValToChar(i)))
   cBin := "1"

   Do While i >0
      i--
      cPotencias2 := ::PotenciaN("2",cValToChar(i))
      If Len(cPotencias2)<Len(cResto)
         cPotencias2:=PadL(cPotencias2,Len(cResto))
      else
         If Len(cPotencias2)>Len(cResto)
            cResto:=PadL(cResto,Len(cPotencias2))
         endif
      endif

      if cPotencias2 <= cResto
         cResto := ::Resta2(cResto, cPotencias2)
         cBin := cBin+"1"
      else
         cBin := cBin+"0"
      endif

   enddo

return cBinToHexN(cBin)

Static Function swap(u,v)
    Local t
    t = u
    u = v
    v = t
Return NIL
 
Ejemplo de uso:

Code: Select all

MsgInfo(TBigInteger():New("123456789201901131637212310000111010000000100003"):ToHex())
Sin embargo, el proceso esta muy lento, tarda como 12 SEGUNDOS en mostar el resultado

Hay que optimizar!!! el codigo

Si alguien tiene tiempo, necesito ayuda para optimizarlo

Saludos

Rolando

Re: Encode Base16

Posted: Fri Feb 01, 2019 12:21 pm
by Marcelo Via Giglio
Hola,

Rolando este no tarda tanto :D

Code: Select all

#include "fivewin.ch"

FUNCTION main()

    MsgInfo(toHex("0001234567890201811151310009990000101010000000100005"))

RETURN NIL


FUNCTION oddsToOne(s)
LOCAL final := RIGHT( ALLTRIM( s ), 1 )
      IF final $ '1,3,5,7,9'
         RETURN '1'  
      ENDIF 
RETURN '0'

FUNCTION divByTwo(s)
LOCAL new_s := '', add := 0, i, new_dgt, ch
             
    FOR i := 1 TO LEN( s )
            ch := SUBSTR(s,i,1)
            new_dgt := INT(( ASC(ch) - ASC('0')) / 2) + add
            new_s   := new_s + alltrim( STR( new_dgt ) )
            add := VAL(oddsToOne(ch)) * 5               
    NEXT

        IF new_s != '0' .AND. LEFT( new_s, 1 ) = '0'
           new_s[1] := 1
        ENDIF

RETURN new_s

FUNCTION toBin( ss )
LOCAL stack := ''

    IF ss == '0'
       stack := '0'
        ELSE

           DO while val(ss) > 0
        stack := oddsToOne( ss ) + stack
                ss := divByTwo( ss )
           ENDDO

        ENDIF 

RETURN stack

FUNCTION toHex(s)
LOCAL binario := toBin(s), i := LEN( binario ), digito, stack := ''
LOCAL digBinarios := {'0000','0001','0010','0011','0100','0101','0110','0111','1000','1001','1010','1011','1100','1101','1110','1111'}
LOCAL digHex      := {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'}

    DO WHILE i > 0
           digito := PADL( SUBSTR( binario, i - 3, 4 ) , 4, '0' )
           stack := digHex[ ASCAN( digBinarios, digito ) ] + stack
           i := i - 4
        ENDDO

RETURN stack
perdón por los identados es que lo hice con notepad

saludos

Re: Encode Base16

Posted: Tue Feb 05, 2019 9:11 am
by Baxajaun
Muchas gracias Marcelo !!!

Saludos