Mega Code Archive

 
Categories / Delphi / Algorithm Math
 

A Fast Formatter for Integers with slow machines

Title: A Fast Formatter for Integers with slow machines Question: How to format integers in machines with slow processors? Answer: For formatting integers as strings with commas (e.g. 12345 = '12,345') the library function usually employed is the FormatFloat function. It is located in the SysUtils unit, and is used as follows: FormatFloat(',0', someInt); However, since this is a function for floating-point numbers, and thus works with floating-point values internally it is inherently slower than an integer-based function. When an integer is passed to it, the integer is silently converted to a float (this is known as promotion), and processing continues normally. With today's increasingly faster math coprocessors, the speed difference between integer and floating-point calculations is steadily decreasing; however, even on newer processors, integer arithmetic is still significantly faster. For comma-formatting integers, using a float function takes up unnecessary computing time. This is not normally a problem when showing a few values, but if you need to do it thousands of times per second, then the wastage adds up. For this, you can use the function presented below. It accepts integers only, and returns a string version of the number with comma-separated thousands groups. function IntToStrComma( Value: integer ): string; (* Very fast inttostr with comma support. Hated using formatfloat() handles negative numbers (20Dec01,4:18p) *) var len, i: integer; buf: array [0..14] of char; isneg: boolean; begin if Value = 0 then begin Result := '0'; Exit; end; asm (* EDX:EAX = dividend, EAX = quotient * ECX = divisor * EDX = remainder * EBX = buf offset * ESI = counter for inserting commas *) PUSH EBX // save regs PUSH ESI XOR EBX, EBX MOV EAX, Value // get num // negative? CMP EAX, 0 JGE @Positive MOV IsNeg, True NEG EAX JMP @WasNeg @Positive: MOV IsNeg, False @WasNeg: // first divide CDQ MOV ECX, 10 IDIV ECX // ans now in EAX, rem in EDX ADD DL, 48 // convert to ascii MOV Byte(buf[EBX]), DL INC EBX MOV ESI, 1 // comma @WhileTop: // WHILE EAX 0 DO CMP EAX, 0 JE @WhileBottom CDQ // these must be done again MOV ECX, 10 IDIV ECX // ans now in EAX, rem in EDX // comma INC ESI CMP ESI, 4 JNE @NoComma MOV byte(buf[EBX]), ',' INC EBX MOV ESI, 1 @NoComma: ADD DL, 48 // convert to ascii // save to string MOV byte(buf[EBX]), DL INC EBX JMP @WhileTop @WhileBottom: // END OF WHILE MOV [len], EBX //INC [len] POP ESI // restore regs POP EBX end; if IsNeg then begin buf[len] := '-'; inc(len); end; (* At this point, buf contains REVERSED string; copy and reverse *) SetLength( Result, len ); for i := 1 to len do begin Result[i] := Char(buf[len-i]); end; end; On newer, faster processors, FormatFloat is almost twice as slow. On slower processors, the difference can be much larger. On a Pentium 1, for example, FormatFloat is more than three times slower. I'm sure this can be made even faster, though. If you do, please let me know.