On Jul 11, 12:19 am, Benjamin White <bjwhite66...@yahoo.dummy.com>
wrote:
The routine below is supposed to convert a String containing decimal
digits to a IBM mainframe Z/series packed decimal number. It seems to
consume a lot of CPU time. Background about this is athttp://benjaminjwhite.name/zdecimal/doc/index.html Is there a faster
way to code this?
/**
* Converts String to packed decimal number. Decimal points, commas and
* spaces are ignored. Sign character is processed. Avoid multiple signs.
* Characters other than digits are invalid and will cause DataException.
* Comma, blank, period, dollar sign and plus are ignored. Scaling and
* exponents are not valid.
*
* @param str
* String of number to convert
* @return byte array of packed decimal, 16 long
*/
public static byte[] stringToPack(String str) throws DataException {
int i; // string index
int j; // byte array index
boolean nibble_ordinal = false;
char ch1;
byte nibble;
int strlen = str.length();
byte[] pknum = new byte[16];
for (i = 0; i < 16; i++) { // initialize to zero
pknum[i] = 0;
}
i = strlen - 1;
j = 15; /* byte index */
pknum[j] = 12; // start with positive sign
while (i > -1) {
ch1 = str.charAt(i);
switch (ch1) {
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
nibble = (byte) Character.getNumericValue(ch1);
if (nibble_ordinal) {
pknum[j] = (byte) (pknum[j] | nibble);
nibble_ordinal ^= true;
} else {
pknum[j] = (byte) (pknum[j] | nibble << 4);
nibble_ordinal ^= true;
--j;
}
--i; // get next char
break;
case ',':
case ' ':
case '.':
case '$':
case '+':
--i; // get next char
break;
case '-':
pknum[15] = (byte) (pknum[15] & 0xf0);
pknum[15] = (byte) (pknum[15] | 0x0d);
--i; // get next char
break;
default:
throw new DataException("Invalid decimal digit: " + ch1);
}
}
return (pknum);
}
Have you actually measured how fast this method runs?
I ask, because I just created a (crude) test program to call it and
its fast - I had to measure in nanoseconds to actually get any
timings.
Sure we can make it faster - but do we need to?
Before optimising, you really need to profile using a good profiler -
not a developers guess. Its often the case that we optimise the wrong
parts of the system and the real bottle neck is left untreated.
Anyway...here's the timing I get on a P4 3Ghz 512 ram Windows PC.
Input: 12345.0
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 35, 69, 12,
Time to convert: 154164ns
Input: -12345.0
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 35, 69, 13,
Time to convert: 18028ns
Input: 9,876,543.0
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, -121, 101, 67, 12,
Time to convert: 22296ns
Input: 1 2345.0
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 35, 69, 12,
Time to convert: 22818ns
Input: $12345.0
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 35, 69, 12,
Time to convert: 17084ns
Input: -$1 2345.0
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 35, 69, 13,
Time to convert: 15455ns
Here's the class I created which has a copy & paste of your method 'as
is'.
package com.amd.sandbox;
public class StringConverter {
/**
* Converts String to packed decimal number. Decimal points, commas
and spaces
* are ignored. Sign character is processed. Avoid multiple signs.
Characters
* other than digits are invalid and will cause DataException.
Comma, blank,
* period, dollar sign and plus are ignored. Scaling and exponents
are not
* valid.
*
* @param str
* String of number to convert
* @return byte array of packed decimal, 16 long
*/
public static byte[] stringToPack(String str) throws Exception {
int i; // string index
int j; // byte array index
boolean nibble_ordinal = false;
char ch1;
byte nibble;
int strlen = str.length();
byte[] pknum = new byte[16];
for (i = 0; i < 16; i++) { // initialize to zero
pknum[i] = 0;
}
i = strlen - 1;
j = 15; /* byte index */
pknum[j] = 12; // start with positive sign
while (i > -1) {
ch1 = str.charAt(i);
switch (ch1) {
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
nibble = (byte) Character.getNumericValue(ch1);
if (nibble_ordinal) {
pknum[j] = (byte) (pknum[j] | nibble);
nibble_ordinal ^= true;
} else {
pknum[j] = (byte) (pknum[j] | nibble << 4);
nibble_ordinal ^= true;
--j;
}
--i; // get next char
break;
case ',':
case ' ':
case '.':
case '$':
case '+':
--i; // get next char
break;
case '-':
pknum[15] = (byte) (pknum[15] & 0xf0);
pknum[15] = (byte) (pknum[15] | 0x0d);
--i; // get next char
break;
default:
throw new Exception("Invalid decimal digit: " + ch1);
}
}
return (pknum);
}
public static void main(String[] args) throws Exception {
testWith("12345.0");
testWith("-12345.0");
testWith("9,876,543.0");
testWith("1 2345.0");
testWith("$12345.0");
testWith("-$1 2345.0");
}
private static void testWith(String inputString) throws Exception {
System.out.println("Input: " + inputString);
long startTime = System.nanoTime();
byte[] answer = stringToPack(inputString);
long endTime = System.nanoTime();
for (int i = 0; i < answer.length; i++) {
System.out.print(answer[i] + ", ");
}
System.out.println("\nTime to convert: " + (endTime - startTime)
+"ns");
}
}
Thanks for testing. Someone was complaining that the routine was slow.
It may be called 10 to 100 million times for a large batch of data.
So every little bit of improvement will help.
Thanks everyone for all the good suggestions. I learned alot. I will
try many of the suggestions and test. I may have to call the program
multiple times in a loop to see the differences. If anyone is