JOIN
Get Time
forums   
Search | Watch Thread  |  My Post History  |  My Watches  |  User Settings
View: Flat (newest first)  | Threaded  | Tree
Previous Thread  |  Next Thread
2.1. Converting between Numbers and Strings | Reply
Problem

Converting data between numerical and string formats is another common part of problems in both Algorithm and Marathon tracks. The typical tasks are:
(1) Extract a number from a string containing its notation.
(2) Write a number as a string:
(2.1) integer without special formatting;
(2.2) double without special formatting;
(2.3) integer with leading zeros (for example, 12 as "0012");
(2.4) double with given precision (for example, 123.456 as "0123.4560").

Solution

C++

One of the possible ways (C-style) to accomplish (1) and (2) is to use sscanf and sprintf, respectively.
(1) sscanf(input_string.c_str(), "%d", &output_int);
    sscanf(input_string.c_str(), "%lf", &output_double);
(2) char t[20];
    sprintf(t, "%d", input_int);
    sprintf(t, "%lf", input_double);
    sprintf(t, "%04d", input_int);
    sprintf(t, "%09.4lf", input_double);
    string output_string = string(t);


Java

(1) Use Integer.parseInt() or Double.parseDouble() methods to extract from the string an integer or a floating-point number, correspondingly.
output_int = Integer.parseInt(input_string);
output_double = Double.parseDouble(input_string);


(2.1, 2.2) The basic way to convert a number to a string is simply to add "" to it, which is equivalent to using Integer.toString() or Double.toString() methods.
output_string = input_int+"";
output_string = input_double+"";


(2.3, 2.4) Advanced formatting in Java is done using java.text.NumberFormat class:
NumberFormat nf = NumberFormat.getInstance();
nf.setGroupingUsed(false);		//suppress grouping of integer digits on groups of three
nf.setMinimumIntegerDigits(4);
output_string = nf.format(input_int);

or java.text.DecimalFormat class:
output_string = java.text.DecimalFormat("0000.0000").format(input_int);


C#

(1) Use int.Parse() or double.Parse() methods to extract integer or double, correspondingly:
output_int = int.Parse(input_string);
output_double = double.Parse(input_string);

When extracting a double, you can also use double.Parse(input_string, NumberFormatInfo.InvariantInfo) to ensure that "." will be recognized as decimal separator regardless of locale settings.
(2) Use int.ToString() or double.ToString() instance methods for both regular and advanced formatting.
output_string = input_int.ToString();
output_string = input_double.ToString();
output_string = input_int.ToString("D4");
output_string = input_double.ToString("0000.0000");


VB.NET

(1) No special functions needed:
output_int = input_string
output_double = input_string


(2) For basic formatting you don't need any special functions:
output_string = input_int
output_string = input_double

For advanced formatting, use format() function:
output_string = format(input_int, "0000")
output_string = format(input_double, "0000.0000")
Re: 2.1. Converting between Numbers and Strings (response to post by Nickolas) | Reply
Discussion

The task of getting a number from its string notation usually arises after string fragmentation, when you need to convert some of the extracted text fragments to numbers, and is relatively simple, since each notation represents a number uniquely (except for the case of non-decimal number systems, which is exceedingly rare).

The inverse problem arises when you need to represent numeric computation results as a string of particular format, and can turn trickier, since each number, integer of floating point, can be written in several ways:
- integers can be written with leading zeros, like in time and date notation,
- floating point numbers can have a fixed number of digits before or after decimal point, like in PointLifeGame,
- digits to the left of the decimal point can be separated into groups of three with some separator, like in FormatAmt,
- floating point numbers can be written in scientific format, like in Planets.


In Marathons exotic number formats are rare, since here the main purpose of writing numbers as strings is to be able to pass several related parameters in one string variable. Usually one string represents one problem-specific entity, and numbers written to it are its parameters. Thus, in problems EnclosingCircles, BounceOff and FactoryManager each element of return or input arrays describes the parameters of one placed circle/placed obstacle/process and contract.

Marathon problems don't have a reference solution which could be compared with the return of your solution; each submission is scored by parsing its return and manipulating the results of parsing to produce the score. The parser is written in Java (as well as all server-side processing utilities) and in most cases uses standard Java parsing methods. Thus, unless otherwise stated, the numbers should be written down in any way recognizable by functions Integer.parseInt() and Double.parseDouble(). For example, integer notations can have leading
zeros, and doubles can be written using different numbers of digits after decimal point.

In Algorithms, though, your solution's return must match the return of the reference solution exactly, so the specified format should be met in all detail.


Formatting doubles as strings of special format usually means that you'll have to do some kind of round-off - to round the last digit up, down or according to the given rules. Thus, in PointLifeGame the number has to be rounded down to the nearest ten-thousands, and in PiCalculator standard rounding rules are used (less than five round down, greater than four round up). If negative numbers are allowed (though this is rarely the case), they need some extra attention to distinguish rounding up/down from rounding towards zero/infinity.


Another thing to pay attention is computational speed. Data conversion is a rather slow operation compared to arithmetic, and some conversion methods are significantly slower than the others. If your solution requires a lot of data conversion operations, choose the fastest method or consider changing the approach itself. Consider, for example, problem ApocalypseSomeday. To solve it, one can simple iterate through integer numbers while counting the beastly numbers. The evident way to check whether the number is beastly is to convert it to a string and look for "666" substring within it. This solution passes in Java and in C++ (with sprintf()-based conversion), but fails in C++ with stringstream-based conversion. Alternate solution which uses arithmetic check runs times faster and is totally safe from timing point of view.



Finally, beware of problems which look like they are formatting problems, but which are actually not, or vice versa. Aforementioned PiCalculator deals with numbers which can't be stored in double and even long double types. In Java this problem can be solved as formatting problem using BigDecimal class:

import java.math.BigDecimal;
public class PiCalculator {
	public String calculate(int precision) {
		BigDecimal easy = new BigDecimal("3.141592653589793238462643383279");
		easy = easy.divide(BigDecimal.ONE, precision, BigDecimal.ROUND_HALF_UP);
		return easy.toString();
	}
}


However, in C++ there is no built-in class for long arithmetics, so you have to process Pi not as a number but as a string and do rounding by hand.


FormatAmt is a one-liner problem if you know the tools provided by your language of choice good enough - as long as it's not C++.

In Java you can use standard formatter of decimal numbers:
public class FormatAmt {
	public String amount(int dollars, int cents) {
		return new java.text.DecimalFormat("$#,###,###,##0.00").format(dollars + cents/100.0);
	}
}

or built-in currency formatter:
public class FormatAmt {
	public String amount(int dollars, int cents) {
		return java.text.NumberFormat.getCurrencyInstance().format(dollars + cents/100.0);
	}
}


In C# the solution is the shortest: the required format is standard currency format:
public class FormatAmt {
	public string amount(int dollars, int cents) {
		return (dollars + cents/100.0).ToString("C");
	}
}


In VB.NET it's standard formatter of decimal numbers again:
Public Class FormatAmt
	Public Function amount(dollars As Integer, cents As Integer) As String
		return format(dollars+(cents/100),"$#,###,###,##0.00")
	End Function
End Class



However slow, for most single-shot data conversions in C++ stringstream is a universal tool. It allows to have only one prewritten method for most kinds of conversion operations.
#include <sstream>
#include <iomanip>
 
template<class F, class T> T convert(F input, int width=0, int prec=-1)
{	stringstream A;
	T res;
	if (prec>-1)
		A<<fixed<<setprecision(prec);
	A<<setw(width)<<setfill('0')<<input;
	A>>res;
	return res;
}


Depending on the parameters passed, this method can be used to do basic and most advanced conversions between string and any numerical type.

(1) output_int = convert<string, int>(input_string);
    output_double = convert<string, double>(input_string);
(2) output_string = convert<int, string>(input_int);
    output_string = convert<double, string>(input_double);
    output_string = convert<int, string>(input_int,4);
    output_string = convert<double, string>(input_double,9,4);


stringstream has also other useful flags for more specific formatting like scientific notation, non-decimal number systems etc.
RSS