PB5 : Convert Value to Base N

Share your advanced PureBasic knowledge/code with the community.
User avatar
eddy
Addict
Addict
Posts: 1479
Joined: Mon May 26, 2003 3:07 pm
Location: Nantes

PB5 : Convert Value to Base N

Post by eddy »

- Base N conversion functions

BaseN.pbi

Code: Select all

Procedure.s  IntToBaseN(value.i, baseChars.s)
   ; convert integer number to base N (returns EMPTY if error)
   Protected targetBase = Len(baseChars)
   Protected result.s = ""
   If targetBase < 2 Or targetBase > SizeOf(value)*4 : ProcedureReturn "" : EndIf
   
   Repeat  
      result = PeekS(@baseChars + value % targetBase, 1) + result
      value = value/targetBase
   Until (value <= 0)
   ProcedureReturn result
EndProcedure

Procedure.i BaseNtoInt(strValue.s, baseChars.s)
   ; convert base N number to integer (returns -1 if error)
   Protected targetBase = Len(baseChars)
   Protected result = 0
   If targetBase < 2 Or targetBase > SizeOf(result)*4 : ProcedureReturn -1 : EndIf
   
   For i = 1 To Len(strValue)
      v = FindString(baseChars, Mid(strValue, i, 1)) - 1
      If v = -1 : ProcedureReturn -1 : EndIf ; 
      result * targetBase + v
   Next 
   
   ProcedureReturn result
EndProcedure

Code: Select all

Debug IntToBaseN(101,"01") ;<---- Bin = base2

For i=0 To 15
   Debug IntToBaseN(i,"0123456789ABCDEF") ;<---- Hexa = base16 
Next 

customBase.s="ABCDEFGHIJKLMNOPQRSTUVWXYZ_"
Debug IntToBaseN(7561231232,customBase); <--- custom Base
Debug BaseNtoInt("TNZVJIF",customBase)

CompilerIf #PB_Compiler_Processor=#PB_Processor_x64
   If (BaseNtoInt(IntToBaseN(9223372036854775807,customBase),customBase)=9223372036854775807)
      Debug "Result is correct - BaseN functions work!"
   EndIf 
CompilerElse 
   If (BaseNtoInt(IntToBaseN(2147483647,customBase),customBase)=2147483647)
      Debug "Result is correct - BaseN functions work!"
   EndIf 
CompilerEndIf
Last edited by eddy on Fri Jul 26, 2013 1:12 pm, edited 7 times in total.
Imagewin10 x64 5.72 | IDE | PB plugin | Tools | Sprite | JSON | visual tool
User avatar
Joakim Christiansen
Addict
Addict
Posts: 2452
Joined: Wed Dec 22, 2004 4:12 pm
Location: Norway
Contact:

Re: Convert Value to Base N

Post by Joakim Christiansen »

Better/shorter than the one I wrote some time ago, very clever :D

EDIT:
It can be made even shorter if you replace:

Code: Select all

CompilerIf #PB_Compiler_Processor = #PB_Processor_x64
  ;64 is the worst cast buffer size For base 2 And int.MaxValue
  If targetBase>64 : ProcedureReturn "" : EndIf 
CompilerElse 
  ;32 is the worst cast buffer size For base 2 And int.MaxValue
  If targetBase>32 : ProcedureReturn "" : EndIf 
CompilerEndIf
With:

Code: Select all

If targetBase>SizeOf(value)*4 : ProcedureReturn "" : EndIf
I like logic, hence I dislike humans but love computers.
User avatar
eddy
Addict
Addict
Posts: 1479
Joined: Mon May 26, 2003 3:07 pm
Location: Nantes

Re: Convert Value to Base N

Post by eddy »

code updated :wink:
Imagewin10 x64 5.72 | IDE | PB plugin | Tools | Sprite | JSON | visual tool
User avatar
BasicallyPure
Enthusiast
Enthusiast
Posts: 539
Joined: Thu Mar 24, 2011 12:40 am
Location: Iowa, USA

Re: Convert Value to Base N

Post by BasicallyPure »

This was a nice addition to my bag of tricks.
Thanks.

So I was thinking how could the process be reversed to convert a Base N to integer.
This is what I came up with.
It seems to be working as far as I have tested it.
I could use some help with checking for error conditions.
I didn't fully understand the use of 'SizeOf()' in the error check.

In theory using both procedures together could convert any base to any other base.

BP.

Code: Select all

Procedure.s  IntToBaseN(value.i, baseChars.s)
   ; convert integer number to base N
   Protected targetBase = Len(baseChars)
   Protected result.s = ""
   
   ; returns EMPTY if error
   If targetBase < 2 Or targetBase > SizeOf(value)*4 : ProcedureReturn "" : EndIf
   
   Repeat  
      result = PeekS(@baseChars + value % targetBase, 1) + result
      value = value/targetBase
   Until (value <= 0)
   
   ProcedureReturn result
EndProcedure

Procedure BaseNtoInt(strValue.s, baseChars.s)
   ; convert base N number to integer
   Protected base = Len(baseChars)
   Protected j = Len(strValue)
   Protected exp = j
   Protected value, v
   
   For i = 1 To j
      exp - 1
      v = FindString(baseChars, Mid(strValue, i, 1)) - 1
      If v = -1 : ProcedureReturn -1 : EndIf ; if error return -1
      value + (v * Pow(base, exp))
   Next i
   
    ProcedureReturn value
EndProcedure



Debug IntToBaseN(309,"01") ;<---- Bin = base2
Debug BaseNtoInt("100110101", "01")
Debug ""

Debug IntToBaseN(7561231232,"ABCDEFGHIJKLMNOPQRSTUVWXYZ_"); <--- custom Base
Debug BaseNtoInt("TNZVJIF", "ABCDEFGHIJKLMNOPQRSTUVWXYZ_")
Debug ""

Debug IntToBaseN(55, "01234567") ;<--- Octal
Debug BaseNtoInt("67", "01234567")
edit: added error check
Last edited by BasicallyPure on Tue Mar 05, 2013 2:50 am, edited 3 times in total.
BasicallyPure
Until you know everything you know nothing, all you have is what you believe.
User avatar
skywalk
Addict
Addict
Posts: 4220
Joined: Wed Dec 23, 2009 10:14 pm
Location: Boston, MA

Re: Convert Value to Base N

Post by skywalk »

The nice thing about standards is there are so many to choose from. ~ Andrew Tanenbaum
User avatar
eddy
Addict
Addict
Posts: 1479
Joined: Mon May 26, 2003 3:07 pm
Location: Nantes

Re: Convert Value to Base N

Post by eddy »

BasicallyPure wrote:In theory using both procedures together could convert any base to any other base.
There is a minor bug in your last function

Code: Select all

 If v < 0 : ProcedureReturn -1 : EndIf
Imagewin10 x64 5.72 | IDE | PB plugin | Tools | Sprite | JSON | visual tool
User avatar
BasicallyPure
Enthusiast
Enthusiast
Posts: 539
Joined: Thu Mar 24, 2011 12:40 am
Location: Iowa, USA

Re: Convert Value to Base N

Post by BasicallyPure »

eddy wrote:There is a minor bug in your last function
oops, here is what it should be.

Code: Select all

If v = -1 : ProcedureReturn -1 : EndIf
Your way, v < 0 works too.
BasicallyPure
Until you know everything you know nothing, all you have is what you believe.
wilbert
PureBasic Expert
PureBasic Expert
Posts: 3942
Joined: Sun Aug 08, 2004 5:21 am
Location: Netherlands

Re: Convert Value to Base N

Post by wilbert »

Here's a different way using a global table.
It's faster if you are not switching base all the time.
Also the Repeat/Until and While/Wend blocks inside the conversion procedures should be easy to convert to ASM if speed it really important.

Code: Select all

Structure BaseN_Table
  n.a[256]
EndStructure

Global IntToBaseN_Table.BaseN_Table
Global BaseNtoInt_Table.BaseN_Table
Global BaseN_TargetBase

Procedure SetBaseChars(baseChars.s)
  Protected *c.Character = @baseChars
  FillMemory(@IntToBaseN_Table, 256, 255, #PB_Ascii)
  FillMemory(@BaseNtoInt_Table, 256, 255, #PB_Ascii)
  BaseN_TargetBase = 0
  While *c\c
    IntToBaseN_Table\n[BaseN_TargetBase] = *c\c
    BaseNtoInt_Table\n[*c\c] = BaseN_TargetBase
    BaseN_TargetBase + 1
    *c + SizeOf(Character)
  Wend
EndProcedure

Procedure.s IntToBaseN(value.i, baseChars.s = "")
  Protected result.s, *c.Character, v
  
  If baseChars : SetBaseChars(baseChars) : EndIf
  If BaseN_TargetBase < 2 : ProcedureReturn "" : EndIf
  
  If value : v = Round(Log(value)/Log(BaseN_TargetBase), #PB_Round_Up) : Else : v = 1 : EndIf
  
  result = Space(v)
  *c = @result + (v - 1) * SizeOf(Character)
  Repeat
    v = value
    value / BaseN_TargetBase
    v - value * BaseN_TargetBase
    *c\c = IntToBaseN_Table\n[v]
    *c - SizeOf(Character)
  Until value <= 0
  
  ProcedureReturn result
EndProcedure

Procedure BaseNtoInt(strValue.s, baseChars.s = "")
  Protected result.i = 0, *c.Ascii, v
  
  If baseChars : SetBaseChars(baseChars) : EndIf
  If BaseN_TargetBase < 2 : ProcedureReturn -1 : EndIf
  
  *c = @strValue
  While *c\a
    v = BaseNtoInt_Table\n[*c\a]
    If v = 255
      result = -1
      Break
    Else
      result * BaseN_TargetBase
      result + v
      *c + SizeOf(Character)
    EndIf
  Wend
  
  ProcedureReturn result
EndProcedure


SetBaseChars("01")
Debug IntToBaseN(309) ;<---- Bin = base2
Debug BaseNtoInt("100110101")
Debug ""

SetBaseChars("ABCDEFGHIJKLMNOPQRSTUVWXYZ_")
Debug IntToBaseN(7561231232); <--- custom Base
Debug BaseNtoInt("TNZVJIF")
Debug ""
 
SetBaseChars("01234567")
Debug IntToBaseN(55) ;<--- Octal
Debug BaseNtoInt("67")
Windows (x64)
Raspberry Pi OS (Arm64)
Post Reply