• We’re currently investigating an issue related to the forum theme and styling that is impacting page layout and visual formatting. The problem has been identified, and we are actively working on a resolution. There is no impact to user data or functionality, this is strictly a front-end display issue. We’ll post an update once the fix has been deployed. Thanks for your patience while we get this sorted.

Java methods to do C atoi() or atof() functionality?

I have a small array of doubles that I fill with data. Then, since a Datagram can only transmit a single Java data type and I want to transmit everything in one packet, I build a String with this data by iterating through the array of 7 double elements, delimiting each by a single space, using the concatenation operator '+'. Then I transmit the String, and the receiver will use StreamTokenizer to get each space-delimited value and store it in its own double array.

So at the point of decoding the String into separate double values:

private void getDataFromString(String data)
{
double [] temp = new double[7];
int n = 0;
StringTokenizer st = new StringTokenizer(data);

while (st.hasMoreTokens())
{
temp[n] = st.nextToken(); // OOPS - can't do this of course
n++;
}
}

So the statement I marked with the comment above is obviously the problem; the elements of temp are a double, but the StringTokenizer's nextToken() function return a String. Trying to cast to double didn't work. So it seems like what I would need is an equivalent to the atof() function from C.

Note that I am developing on a Sun SPOT, which uses a Squawk VM and based on the Java Microedition, CLDC compatible. I'm not sure what that all means, but it is possible I don't have all the methods that J2SE has. But I have not found anything I needed but wasn't available yet, so it probably has what I need. Thanks for any help.
 
public static Double valueOf(String s)
throws NumberFormatException

Returns a Double object holding the double value represented by the argument string s.

If s is null, then a NullPointerException is thrown.

Leading and trailing whitespace characters in s are ignored. Whitespace is removed as if by the String.trim() method; that is, both ASCII space and control characters are removed. The rest of s should constitute a FloatValue as described by the lexical syntax rules:

FloatValue:
Signopt NaN
Signopt Infinity
Signopt FloatingPointLiteral
Signopt HexFloatingPointLiteral
SignedInteger

HexFloatingPointLiteral:
HexSignificand BinaryExponent FloatTypeSuffixopt

HexSignificand:
HexNumeral
HexNumeral .
0x HexDigitsopt . HexDigits
0X HexDigitsopt . HexDigits

BinaryExponent:
BinaryExponentIndicator SignedInteger

BinaryExponentIndicator:
p
P

where Sign, FloatingPointLiteral, HexNumeral, HexDigits, SignedInteger and FloatTypeSuffix are as defined in the lexical structure sections of the of the Java Language Specification. If s does not have the form of a FloatValue, then a NumberFormatException is thrown. Otherwise, s is regarded as representing an exact decimal value in the usual "computerized scientific notation" or as an exact hexadecimal value; this exact numerical value is then conceptually converted to an "infinitely precise" binary value that is then rounded to type double by the usual round-to-nearest rule of IEEE 754 floating-point arithmetic, which includes preserving the sign of a zero value. Finally, a Double object representing this double value is returned.

To interpret localized string representations of a floating-point value, use subclasses of NumberFormat.

Note that trailing format specifiers, specifiers that determine the type of a floating-point literal (1.0f is a float value; 1.0d is a double value), do not influence the results of this method. In other words, the numerical value of the input string is converted directly to the target floating-point type. The two-step sequence of conversions, string to float followed by float to double, is not equivalent to converting a string directly to double. For example, the float literal 0.1f is equal to the double value 0.10000000149011612; the float literal 0.1f represents a different numerical value than the double literal 0.1. (The numerical value 0.1 cannot be exactly represented in a binary floating-point number.)

To avoid calling this method on an invalid string and having a NumberFormatException be thrown, the regular expression below can be used to screen the input string:

final String Digits = "(\\p{Digit}+)";
final String HexDigits = "(\\p{XDigit}+)";
// an exponent is 'e' or 'E' followed by an optionally
// signed decimal integer.
final String Exp = "[eE][+-]?"+Digits;
final String fpRegex =
("[\\x00-\\x20]*"+ // Optional leading "whitespace"
"[+-]?(" + // Optional sign character
"NaN|" + // "NaN" string
"Infinity|" + // "Infinity" string

// A decimal floating-point string representing a finite positive
// number without a leading sign has at most five basic pieces:
// Digits . Digits ExponentPart FloatTypeSuffix
//
// Since this method allows integer-only strings as input
// in addition to strings of floating-point literals, the
// two sub-patterns below are simplifications of the grammar
// productions from the Java Language Specification, 2nd
// edition, section 3.10.2.

// Digits ._opt Digits_opt ExponentPart_opt FloatTypeSuffix_opt
"((("+Digits+"(\\.)?("+Digits+"?)("+Exp+")?)|"+

// . Digits ExponentPart_opt FloatTypeSuffix_opt
"(\\.("+Digits+")("+Exp+")?)|"+

// Hexadecimal strings
"((" +
// 0[xX] HexDigits ._opt BinaryExponent FloatTypeSuffix_opt
"(0[xX]" + HexDigits + "(\\.)?)|" +

// 0[xX] HexDigits_opt . HexDigits BinaryExponent FloatTypeSuffix_opt
"(0[xX]" + HexDigits + "?(\\.)" + HexDigits + ")" +

")[pP][+-]?" + Digits + "))" +
"[fFdD]?))" +
"[\\x00-\\x20]*");// Optional trailing "whitespace"

if (Pattern.matches(fpRegex, myString))
Double.valueOf(myString); // Will not throw NumberFormatException
else {
// Perform suitable alternative action
}


Parameters:
s - the string to be parsed.
Returns:
a Double object holding the value represented by the String argument.
Throws:
NumberFormatException - if the string does not contain a parsable number.

From the Sun javadocs, so not sure if your VM supports it, but considering it's in java.lang I would expect it to work just fine.

If that doesn't work, writing your own function is pretty easy.

Think about splitting the string based on the decimal point, then using simple math such as result += ((data[index] - 48) / power); //Assumes an ASCII string

Where power is a function of your offset from the index of the decimal point.

Some of the above from Sun advice still applies too, like running regex's on the string to ensure it's a proper input. Depending on whether you allow negative numbers or not you should check the first character of the string first and trim it off if it is a - or + sign. Store the result of the test in a boolean flag and use that later to apply the sign after all the parsing is done.

 
Use the Java class Double:

private void getDataFromString(String data)
{
double [] temp = new double[7];
int n = 0;
StringTokenizer st = new StringTokenizer(data);

while (st.hasMoreTokens())
{
temp[n] = Double.valueOf(st.nextToken());
n++;
}
}
 
StringTokenizer is deprecated.

Use:

String token[] = data.split(";"); //replace ; with the regexp you want to split on.
 
It may be true that StringTokenizer is deprecated in more recent versions of Java. But just for the sake of simplicity, if you still want to use it anyway, and you are not worried about sanitizing your data, try something like this:

private void getDataFromString(String data)
{
StringTokenizer st = new StringTokenizer(data);
double [] temp = new double[st.countTokens()];
int n = 0;


while (st.hasMoreTokens())
{
temp[n] = Double.parseDouble(st.nextToken());
++n
}
}

Of course you'll want to do things like make sure that your String data is non-null, verify your tokens are not NaN, stuff like that. . .
But like somebody already said, consider steering away from using StringTokenizer. I just didn't want to really harp on that since that wasn't really what your question was about.
 
Thanks. Duh, I hadn't looked in the Double class. I had seen the String class has valueOf() methods that do the opposite of what I need, so you'd think I would go to the Double class. You'd think.... 🙂

I didn't know the StringTokenizer is deprecated. However, it doesn't appear the SunSPOT API has the new String.split() methods. But I'll keep that in mind when using a more recent Java platform.

mosco: It looks like the SunSPOT uses the Java ME CLDC v1.1 libraries.


Thanks all
 
Back
Top