ReverseString()

Share your advanced PureBasic knowledge/code with the community.
AND51
Addict
Addict
Posts: 1040
Joined: Sun Oct 15, 2006 8:56 pm
Location: Germany
Contact:

ReverseString()

Post by AND51 »

Hello!

Here's my code to reverse a string (ABC => CBA), have fun! :lol:

Code: Select all

Procedure.s reverseString(text.s)
	If text
		ProcedureReturn reverseString(PeekS(@text+SizeOf(Character)))+PeekS(@text, 1)
	EndIf
EndProcedure

Debug reverseString("I love PureBasic!")
What about a nice competition? :) Do you think you can beat this? :wink:
PB 4.30

Code: Select all

onErrorGoto(?Fred)
Trond
Always Here
Always Here
Posts: 7446
Joined: Mon Sep 22, 2003 6:45 pm
Location: Norway

Post by Trond »

> 10 times faster:

Code: Select all

Procedure.s ReverseString3(String.s)
  Protected *Start.Character = @String
  Protected *Nd.Character = *Start + Len(String)-1
  While *Start < *Nd
    Swap *Start\c, *Nd\c
    *Start + SizeOf(Character)
    *Nd - SizeOf(Character)
  Wend
  ProcedureReturn String
EndProcedure
AND51
Addict
Addict
Posts: 1040
Joined: Sun Oct 15, 2006 8:56 pm
Location: Germany
Contact:

Post by AND51 »

Very impressive!
You're so fast, because your exchanging data in which there is a great distance, similar to the QuickSort algorithm.
:D

//Edit: Your code does not work with unicode! Can you correct this?
PB 4.30

Code: Select all

onErrorGoto(?Fred)
User avatar
netmaestro
PureBasic Bullfrog
PureBasic Bullfrog
Posts: 8451
Joined: Wed Jul 06, 2005 5:42 am
Location: Fort Nelson, BC, Canada

Post by netmaestro »

It's fast because arithmetic operations guided by pointers are far faster than stringhandling functions. Little tweak and it's good to go for Ascii or Unicode:

Code: Select all

Procedure.s ReverseString3(String.s) 
  Protected *Start.Character = @String 
  Protected *Nd.Character 
  *Nd.Character = *Start + Len(String)*SizeOf(character)-SizeOf(character)
  While *Start < *Nd 
    Swap *Start\c, *Nd\c 
    *Start + SizeOf(Character) 
    *Nd - SizeOf(Character) 
  Wend 
  ProcedureReturn String 
EndProcedure

BERESHEIT
AND51
Addict
Addict
Posts: 1040
Joined: Sun Oct 15, 2006 8:56 pm
Location: Germany
Contact:

Post by AND51 »

Very nice! Both of you did your job well! :!:
PB 4.30

Code: Select all

onErrorGoto(?Fred)
User avatar
Shardik
Addict
Addict
Posts: 2060
Joined: Thu Apr 21, 2005 2:38 pm
Location: Germany

Post by Shardik »

It's still possible to tweak Trond's solution a little bit further by implementing it in native Assembler:

Code: Select all

Procedure.S ReverseString(String.S)
  Protected StringLength.L

  StringLength = StringByteLength(String)

  !   MOV EAX,DWORD[p.v_String]
  !   MOV ESI,EAX
  !   MOV EDI,EAX
  !   ADD EDI,DWORD[p.v_StringLength]
  !   DEC EDI
  !CheckIfReady:
  !   CMP ESI,EDI
  !   JNB Ready
  !   MOV BL,[ESI]
  !   MOV BH,[EDI]
  !   MOV [EDI],BL
  !   MOV [ESI],BH
  !   INC ESI
  !   DEC EDI
  !   JMP CheckIfReady
  !Ready:

  ProcedureReturn String
EndProcedure


Count.L
StartTime.L

StartTime = ElapsedMilliseconds()

Repeat 
  ReverseString("I love PureBASIC!")
  Count + 1 
Until ElapsedMilliseconds() - StartTime >= 1000 

MessageRequester("Cycle count", Str(Count), #MB_ICONINFORMATION)
Measured cycles on my PC:
AND51: ~ 0.16 million
Trond + netmaestro: ~ 2.1 million
Shardik: ~ 2.4 million

It's always quite interesting to compare different algorithms and in most cases my predictions have been proven wrong... :wink:
I've also tried to copy 4 bytes at once which should be faster but with the above short example string the payoff for aligning the string on a word boundary and fill it up with spaces to a size divideable by 8 takes too much time.

Even my first approach of using two strings

Code: Select all

Procedure.S ReverseString(String1.S)
  Protected String2.S
  Protected StringLength.L

  StringLength = Len(String1)
  String2 = Space(StringLength)

!   MOV ESI,DWORD[p.v_String1]
!   MOV EDI,DWORD[p.v_String2]
!   MOV ECX,DWORD[p.v_StringLength]
!   ADD EDI,ECX
!   DEC EDI
!CopyLoop:
!   MOV AL,[ESI]
!   MOV [EDI],AL
!   INC ESI
!   DEC EDI
!   LOOP CopyLoop
!   MOV EAX,EDI

  ProcedureReturn String2
EndProcedure
is quite slow with about 1.4 million cycles. Unfortuately it's not possible to make use of the powerful move string instruction MOVS with REP prefix because one index register has to be incremented and the other has to be decremented... :cry:
Post Reply