c++ stringstream is too slow, how to speed up? [duplicate] - c++

This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
Fastest way to read numerical values from text file in C++ (double in this case)
#include <ctime>
#include <cstdlib>
#include <string>
#include <sstream>
#include <iostream>
#include <limits>
using namespace std;
static const double NAN_D = numeric_limits<double>::quiet_NaN();
void die(const char *msg, const char *info)
{
cerr << "** error: " << msg << " \"" << info << '\"';
exit(1);
}
double str2dou1(const string &str)
{
if (str.empty() || str[0]=='?') return NAN_D;
const char *c_str = str.c_str();
char *err;
double x = strtod(c_str, &err);
if (*err != 0) die("unrecognized numeric data", c_str);
return x;
}
static istringstream string_to_type_stream;
double str2dou2(const string &str)
{
if (str.empty() || str[0]=='?') return NAN_D;
string_to_type_stream.clear();
string_to_type_stream.str(str);
double x = 0.0;
if ((string_to_type_stream >> x).fail())
die("unrecognized numeric data", str.c_str());
return x;
}
int main()
{
string str("12345.6789");
clock_t tStart, tEnd;
cout << "strtod: ";
tStart=clock();
for (int i=0; i<1000000; ++i)
double x = str2dou1(str);
tEnd=clock();
cout << tEnd-tStart << endl;
cout << "sstream: ";
tStart=clock();
for (int i=0; i<1000000; ++i)
double x = str2dou2(str);
tEnd=clock();
cout << tEnd-tStart << endl;
return 0;
}
strtod: 405
sstream: 1389
update: remove undersocres, env: win7+vc10

C/C++ text to number formatting is very slow. Streams are horribly slow but even C number parsing is slow because it's quite difficult to get it correct down to the last precision bit.
In a production application where reading speed was important and where data was known to have at most three decimal digits and no scientific notation I got a vast improvement by hand-coding a floating parsing function handling only sign, integer part and any number of decimals (by "vast" I mean 10x faster compared to strtod).
If you don't need exponent and the precision of this function is enough this is the code of a parser similar to the one I wrote back then. On my PC it's now 6.8 times faster than strtod and 22.6 times faster than sstream.
double parseFloat(const std::string& input)
{
const char *p = input.c_str();
if (!*p || *p == '?')
return NAN_D;
int s = 1;
while (*p == ' ') p++;
if (*p == '-') {
s = -1; p++;
}
double acc = 0;
while (*p >= '0' && *p <= '9')
acc = acc * 10 + *p++ - '0';
if (*p == '.') {
double k = 0.1;
p++;
while (*p >= '0' && *p <= '9') {
acc += (*p++ - '0') * k;
k *= 0.1;
}
}
if (*p) die("Invalid numeric format");
return s * acc;
}

string stream is slow. Quite very slow. If you are writing anything performance critical that acts on large data sets ( say loading assets after a level change during a game ) do not use string streams. I recommend using the old school c library parsing functions for performance, although I cannot say how they compare to something like boost spirit.
However, compared to c library functions, string streams are very elegant, readable and reliable so if what you are doing is not performance ciritcal I recommend sticking to streams.

In general, if you need speed, consider this library:
http://www.fastformat.org/
(I'm not sure if it contains functions for converting strings or streams to other types, though, so it may not answer your current example).
For the record, please note you're comparing apples to oranges here. strtod() is a simple function that has a single purpose (converting strings to double), while stringstream is a much more complex formatting mechanism, which is far from being optimized to that specific purpose. A fairer comparison would be comparing stringstream to the sprintf/sscanf line of functions, which would be slower than strtod() but still faster than stringstream. I'm not exactly sure what makes stringstream's design slower than sprintf/sscanf, but it seems like that's the case.

Have you considered using lexical_cast from boost?
http://www.boost.org/doc/libs/1_46_1/libs/conversion/lexical_cast.htm
Edit: btw, the clear() should be redundant.

Related

C++ program for converting decimal to binary

I need to program a method that will pass two int numbers i1 and i2
and return the number that has more ones in its binary representation.
This thread should help you get the binary representations
C++ - Decimal to binary converting
later with your binary arrays you can use
#include <numeric>
std::accumulate(binaryArr, binaryArr + sizeof(binaryArr)/sizeof(binaryArr[0]), 0);
to count the number of ones.
Also this really looks like solve my homework for me type of question, try reaserching and solving the problem yourself, and then asking your question with some code samples. This way you actually learn
first of all you should find way to find how many ones contains number(count_ones_binary function), and then you just use this function to solve you problem
#include <iostream>
int count_ones_binary(int x)
{
int res = 0;
while (x != 0)
{
if (x % 2 != 0)
res++;
x /= 2;
}
return res;
}
void more_ones_binary(int i1, int i2)
{
int count_i1 = count_ones_binary(i1);
int count_i2 = count_ones_binary(i2);
if (count_i1 > count_i2)
std::cout << "i1 have more ones\n";
else if (count_i1 < count_i2)
std::cout << "i2 have more ones\n";
else std::cout << "equal\n";
}

Converting a floating point number to string with MPFR

I want to convert a MPFR floating point number into a string.
If I run my program the string is generated but without the "." in the number. How can I do it right?
#include <stdlib.h>
#include <string.h>
#include <iostream>
#include <mpreal.h>
using mpfr::mpreal;
using std::cout;
using std::endl;
int main (int ac, char *av[])
{
char data[255];
mpreal x = 42.0, y = 3.14159265358979323846, res = 0.0;
mp_exp_t exponent = 10;
// string data_str[256];
int precision = 50;
res = x * y;
cout.precision(100);
cout << res;
cout << "\n";
// if (mpfr_snprintf (data, 254, "%.20Ff", res.mpfr_srcptr()) < 0)
/*
if (mpfr_snprintf (data, 254, "%.20Ff", res.mpfr_srcptr()) < 0)
{
cout << "gmp_prints_float: error saving string!\n";
}
*/
mpfr_get_str ((char *) &data, &exponent, 10, precision, res.mpfr_srcptr(), GMP_RNDN);
cout << data;
cout << "\n";
mpfr_free_cache ();
}
131.946891450771317977341823279857635498046875
13194689145077131797734182327985763549804687500000
There is no decimal point in the string output!
From the documentation
The generated string is a fraction, with an implicit radix point immediately to the left of the first digit. For example, the number -3.1416 would be returned as "-31416" in the string and 1 written at expptr.
It is up to you to generate a human-readable representation fron the string and the exponent.
An alternative would be to use mpfr_sprintf.
MPFR's mpfr_get_str function is copied on GMP's mpf_get_str function, explaining why it has been chosen not to write a decimal point. There are two solutions to have a decimal point:
Use mpfr_sprintf (or some variant), as suggested in this answer. I would recommend this solution (perhaps unless you want to ignore the locales), as it is the most flexible in the output format and does not need a correction.
If you just want the significand with an explicit decimal point, use mpfr_get_str, but with a pointer buffer+1 instead of buffer. Then, do something like (disregarding the locales)
int neg = buffer[1] == '-';
if (neg)
buffer[0] = '-';
buffer[neg] = '.';
after filtering the special cases (NaN and infinities).

Converting a string of numbers to any form of an int

As a part of a larger program, I must convert a string of numbers to an integer(eventually a float). Unfortunately I am not allowed to use casting, or atoi.
I thought a simple operation along the lines of this:
void power10combiner(string deciValue){
int result;
int MaxIndex=strlen(deciValue);
for(int i=0; MaxIndex>i;i++)
{
result+=(deciValue[i] * 10**(MaxIndex-i));
}
}
would work. How do I convert a char to a int? I suppose I could use ASCII conversions, but I wouldn't be able to add chars to ints anyways(assuming that the conversion method is to have an enormous if statement that returns the different numerical value behind each ASCII number).
There are plenty of ways to do this, and there are some optimization and corrections that can be done to your function.
1) You are not returning any value from your function, so the return type is now int.
2) You can optimize this function by passing a const reference.
Now for the examples.
Using std::stringstream to do the conversion.
int power10combiner(const string& deciValue)
{
int result;
std::stringstream ss;
ss << deciValue.c_str();
ss >> result;
return result;
}
Without using std::stringstream to do the conversion.
int power10combiner(const string& deciValue)
{
int result = 0;
for (int pos = 0; deciValue[pos] != '\0'; pos++)
result = result*10 + (deciValue[pos] - '0');
return result;
}
EDITED by suggestion, and added a bit of explanation.
int base = 1;
int len = strlen(deciValue);
int result = 0;
for (int i = (len-1); i >= 0; i--) { // Loop right to left. Is this off by one? Too tired to check.
result += (int(deciValue[i] - '0') * base); // '0' means "where 0 is" in the character set. We are doing the conversion int() because it will try to multiply it as a character value otherwise; we must cast it to int.
base *= 10; // This raises the base...it's exponential but simple and uses no outside means
}
This assumes the string is only numbers. Please comment if you need more clarification.
You can parse a string iteratively into an integer by simply implementing the place-value system, for any number base. Assuming your string is null-terminated and the number unsigned:
unsigned int parse(const char * s, unsigned int base)
{
unsigned int result = 0;
for ( ; *s; ++s)
{
result *= base;
result += *s - '0'; // see note
}
return result;
}
As written, this only works for number bases up to 10 using the numerals 0, ..., 9, which are guaranteed to be arranged in order in your execution character set. If you need larger number bases or more liberal sets of symbols, you need to replace *s - '0' in the indicated line by a suitable lookup mechanism that determines the digit value of your input character.
I would use std::stringstream, but nobody posted yet a solution using strtol, so here is one. Note, it doesn't perform handle out-of-range errors. On unix/linux you can use errno variable to detect such errors(by comparing it to ERANGE).
BTW, there are strtod/strtof/strtold functions for floating-point numbers.
#include <iostream>
#include <cstdlib>
#include <string>
int power10combiner(const std::string& deciValue){
const char* str = deciValue.c_str();
char* end; // the pointer to the first incorrect character if there is such
// strtol/strtoll accept the desired base as their third argument
long int res = strtol(str, &end, 10);
if (deciValue.empty() || *end != '\0') {
// handle error somehow, for example by throwing an exception
}
return res;
}
int main()
{
std::string s = "100";
std::cout << power10combiner(s) << std::endl;
}

How would I convert decimal into binary?

All I really know is PHP and I used the decbin function etc, It was fairly easy to do. In this C++ program I want to do the same thing, just a simple number or string how would I do this?
A simple function could be defined such as this:
void binary(int decimal) {
int remainder;
if(decimal <= 1) {
std::cout << decimal;
return;
}
remainder = decimal % 2;
binary(decimal >> 1);
std::cout << remainder;
}
Although there are many other resources on the web on how to do this..
A noteworthy question for efficiency of it here, as you may want more than just that:
Efficiently convert between Hex, Binary, and Decimal in C/C++
you can do this non-recursively using something like this:
std::string Dec2Bin(int nValue, bool bReverse = false)
{
std::string sBin;
while(nValue != 0)
{
sBin += (nValue & 1) ? '1' : '0';
nValue >>= 1;
}
if(!bReverse)
std::reverse(sBin.begin(),sBin.end());
return sBin;
}
of course this isn't too architucture friendly, but it avoids cout, just incase your not using a console. it also outputs in any bit ordering.
You can use itoa if it's available on your compiler. Just remember it's not standard and if you need a standard method you're better off using the other solutions posted.
If you want to print it, just use this code here. If you want to return a string, instead of using cout, append to a C++ string instead.
offering the iterative approach (pardon the #defines (but i'm quite sure they will be compiled to the expression's value), i don't quite remember predefined macro/constants in C):
#define INT_ARCH 32
#define ARCH_SHIFTABLE (INT_ARCH - 1)
#define ARCH_MAX_INT 1 << ARCH_SHIFTABLE
void dec_to_bin(int decimal)
{
int shifter = ARCH_MAX_INT;
for(; shifter > 0; shifter >>= 1)
cout << (decimal & shifter);
}
Similar to #Necrolis answer without the need for an if, and the reversal of the string.
string decimalToBinary(int decimal) {
string binary;
while(decimal) {
binary.insert(0, 1, (decimal & 1) + '0');
decimal >>= 1;
}
return binary;
}
Do with simple way in c++
#include <iostream>
using namespace std;
int main()
{
long n, rem, binary=0, i=1;
cout<<"Enter a int: ";
cin>>n;
while(n != 0)
{
rem = n%2;
n = n/2;
binary= binary + (rem*i);
i = i*10;
}
cout<< "\nAns: "<<binary <<endl;
return 0;
}

Simplifying my program to convert numbers to from one base to another

I'm taking a beginner C++ course. I received an assignment telling me to write a program that converts an arbitrary number from any base between binary and hex to another base between binary and hex. I was asked to use separate functions to convert to and from base 10. It was to help us get used to using arrays. (We already covered passing by reference previously in class.) I already turned this in, but I'm pretty sure this wasn't how I was meant to do it:
#include <iostream>
#include <conio.h>
#include <cstring>
#include <cmath>
using std::cout;
using std::cin;
using std::endl;
int to_dec(char value[], int starting_base);
char* from_dec(int value, int ending_base);
int main() {
char value[30];
int starting_base;
int ending_base;
cout << "This program converts from one base to another, so long as the bases are" << endl
<< "between 2 and 16." << endl
<< endl;
input_numbers:
cout << "Enter the number, then starting base, then ending base:" << endl;
cin >> value >> starting_base >> ending_base;
if (starting_base < 2 || starting_base > 16 || ending_base < 2 || ending_base > 16) {
cout << "Invalid base(s). ";
goto input_numbers;
}
for (int i=0; value[i]; i++) value[i] = toupper(value[i]);
cout << "Base " << ending_base << ": " << from_dec(to_dec(value, starting_base), ending_base) << endl
<< "Press any key to exit.";
getch();
return 0;
}
int to_dec(char value[], int starting_base) {
char hex[16] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};
long int return_value = 0;
unsigned short int digit = 0;
for (short int pos = strlen(value)-1; pos > -1; pos--) {
for (int i=0; i<starting_base; i++) {
if (hex[i] == value[pos]) {
return_value+=i*pow((float)starting_base, digit++);
break;
}
}
}
return return_value;
}
char* from_dec(int value, int ending_base) {
char hex[16] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};
char *return_value = (char *)malloc(30);
unsigned short int digit = (int)ceil(log10((double)(value+1))/log10((double)ending_base));
return_value[digit] = 0;
for (; value != 0; value/=ending_base) return_value[--digit] = hex[value%ending_base];
return return_value;
}
I'm pretty sure this is more advanced than it was meant to be. How do you think I was supposed to do it?
I'm essentially looking for two kinds of answers:
Examples of what a simple solution like the one my teacher probably expected would be.
Suggestions on how to improve the code.
I don't think you need the inner loop:
for (int i=0; i<starting_base; i++) {
What is its purpose?
Rather, you should get the character at value[ pos ] and convert it to an integer. The conversion depends on base, so it may be better to do it in a separate function.
You are defining char hex[ 16 ] twice, once in each function. It may better to do it at only one place.
EDIT 1:
Since this is "homework" tagged, I cannot give you the full answer. However, here is an example of how to_dec() is supposed to work. (Ideally, you should have constructed this!)
Input:
char * value = 3012,
int base = 4,
Math:
Number = 3 * 4^3 + 0 * 4^2 + 1 * 4^1 + 2 * 4^0 = 192 + 0 + 4 + 2 = 198
Expected working of the loop:
x = 0
x = 4x + 3 = 3
x = 4x + 0 = 12
x = 4x + 1 = 49
x = 4x + 2 = 198
return x;
EDIT 2:
Fair enough! So, here is some more :-)
Here is a code sketch. Not compiled or tested though. This is direct translation of the example I provided earlier.
unsigned
to_dec( char * inputString, unsigned base )
{
unsigned rv = 0; // return value
unsigned c; // character converted to integer
for( char * p = inputString; *p; ++p ) // p iterates through the string
{
c = *p - hex[0];
rv = base * rv + c;
}
return rv;
}
I would stay away from GOTO statements unless they are absolutely necessary. GOTO statements are easy to use but will lead to 'spaghetti code'.
Try using a loop instead. Something along the lines of this:
bool base_is_invalid = true;
while ( base_is_invalid ) {
cout << "Enter the number, then starting base, then ending base:" << endl;
cin >> value >> starting_base >> ending_base;
if (starting_base < 2 || starting_base > 16 || ending_base < 2 || ending_base > 16)
cout << "Invalid number. ";
else
base_is_invalid = false;
}
You can initialize arrays by string literals (notice that the terminating \0 is not included because the size of the array doesn't permit that):
char const hex[16] = "0123456789ABCDEF";
Or just use a pointer to the string literal for the same effect:
char const* hex = "0123456789ABCDEF";
to_dec() looks to complicated, here is my shot at it:
int to_dec(char* value, int starting_base)
{
int return_value = 0;
for (char* cur = value + strlen(value) - 1; cur >= value; cur--) {
// assuming chars are ascii/utf: 0-9=48-57, A-F=65-70
// faster than loop
int inval = *cur - 48;
if (inval > 9) {
inval = *cur - 55;
if (inval > 15) {
// throw input error
}
}
if (inval < 0) {
// throw input error
}
if (inval >= starting_base) {
// throw input error
}
// now the simple calc
return_value *= starting_base;
return_value += inval;
}
return return_value;
}
for the initial conversion from ascii to an integer, you can also use a lookup table (just as you are using a lookuptable to to the conversion the other way around) , which is much faster then searching through the array for every digit.
int to_dec(char value[], int starting_base)
{
char asc2BaseTab = {0,1,2,3,4,5,6,7,8,9,-1,-1,-1,-1,-1,-1,-1,10,11,12,13,14,15, //0-9 and A-F (big caps)
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, //unused ascii chars
10,11,12,13,14,15}; //a-f (small caps)
srcIdx = strlen(value);
int number=0;
while((--srcIdx) >= 0)
{
number *= starting_base;
char asciiDigit = value[srcIdx];
if(asciiDigit<'0' || asciiDigit>'f')
{
//display input error
}
char digit = asc2BaseTab[asciiDigit - '0'];
if(digit == -1)
{
//display input error
}
number += digit;
}
return number;
}
p.s. excuses if there are some compile errors in this...I couldn't test it...but the logic is sound.
In your description of the assignment as given it says:
"I was asked to use separate functions to convert to and from base 10."
If that is really what the teacher meant and wanted, which is doubtful, your code doesn't do that:
int to_dec(char value[], int starting_base)
is returning an int which is a binary number. :-) Which in my opinion does make more sense.
Did the teacher even notice that?
C and C++ are different languages, and with different styles of programming. You better not to mix them. (Where C and C++ differ)
If you are trying to use C++, then:
Use std::string instead of char* or char[].
int to_dec(string value, int starting_base);
string from_dec(int value, int ending_base);
No any mallocs, use new/delete. But actually C++ manages memory automatically. The memory is freed as soon as variable is out of scope (unless you are dealing with pointers). And pointers are the last thing you need to deal with.
We don't need here any lookup tables, just a magic string.
string hex = "0123456789ABCDEF";//The index of the letter is its decimal value. A is 10, F is 15.
//usage
char c = 'B';
int value = hex.find( c );//works only with uppercase;
The refactored to_dec can be like that.
int to_dec(string value, int starting_base) {
string hex = "0123456789ABCDEF";
int result = 0;
for (int power = 0; power < value.size(); ++power) {
result += hex.find( value.at(value.size()-power-1) ) * pow((float)starting_base, power);
}
return result;
}
And there is a more elegant algorithm to convert from base 10 to any other
See there for example. You have the opportunity to code it yourself :)
In your from_dec function, you're converting the digits from left to right. An alternative is to convert from right to left. That is,
std::string from_dec(int n, int base)
{
std::string result;
bool is_negative = n < 0;
if (is_negative)
{
n = - n;
}
while (n != 0)
{
result = DIGITS[n % base] + result;
n /= base;
}
if (is_negative)
{
result = '-' + result;
}
return result;
}
This way, you won't need the log function.
(BTW, to_dec and from_dec are inaccurate names. Your computer doesn't store numbers in base 10.)
Got this question on an interview once and brainfarted and spun wheels for a while. Go figure. Anyway, a couple years later I'm going through Math and Physics for Programmers to brush up for positions that are more math intensive than what I've been doing. CH1 "assignment" has
// Write a function ConvertBase(Number, Base1, Base2) which takes a
// string or array representing an integer in Base1 and converts it
// into base Base2, returning the new string.
So, I took an approach mentioned above: I convert string in arbitrary base to UINT64, then I convert UINT64 back to arbitrary base:
CString ConvertBase(const CString& strNumber, int base1, int base2)
{
return ValueToBaseString(BaseStringToValue(strNumber, base1), base2);
}
Each of the subfunctions has a recursive solution. Here's one for example:
UINT64 BaseStringToValue(const CString& strNumber, int base)
{
if (strNumber.IsEmpty())
{
return 0;
}
CString outDigit = strNumber.Right(1);
UINT64 output = DigitToInt(outDigit[0]);
CString strRemaining = strNumber.Left(strNumber.GetLength() - 1);
UINT64 val = BaseStringToValue(strRemaining, base);
output += val * base;
return output;
}
I find the other one slightly harder to grasp mentally, but it works roughly the same way.
I also implemented DigitToInt and IntToDigit which work just like they sound. You can take some neat shortcuts there, by the way, if you realize that chars are ints then you don't need huge switch statements:
int DigitToInt(wchar_t cDigit)
{
cDigit = toupper(cDigit);
if (cDigit >= '0' && cDigit <= '9')
{
return cDigit - '0';
}
return cDigit - 'A' + 10;
}
and unit tests are really your friend here:
typedef struct
{
CString number;
int base1;
int base2;
CString answer;
} Input;
Input input[] =
{
{ "345678", 10, 16, "5464E"},
{ "FAE211", 16, 8, "76561021" },
{ "FAE211", 16, 2, "111110101110001000010001"},
{ "110110111", 2, 10, "439" }
};
(snip)
for (int i = 0 ; i < sizeof(input) / sizeof(input[0]) ; i++)
{
CString result = ConvertBase(input[i].number, input[i].base1, input[i].base2);
printf("%S in base %d is %S in base %d (%S expected - %s)\n", (const WCHAR*)input[i].number,
input[i].base1,
(const WCHAR*) result,
input[i].base2,
(const WCHAR*) input[i].answer,
result == input[i].answer ? "CORRECT" : "WRONG");
}
And here's the output:
345678 in base 10 is 5464E in base 16 (5464E expected - CORRECT)
FAE211 in base 16 is 76561021 in base 8 (76561021 expected - CORRECT)
FAE211 in base 16 is 111110101110001000010001 in base 2 (111110101110001000010001 expected - CORRECT)
110110111 in base 2 is 439 in base 10 (439 expected - CORRECT)
Now I took some shortcuts in coding by using CString types, etc. I was giving no consideration to efficiency or performance, I just wanted to solve the algorithm with easiest coding possible.
It can help to understand how these algorithms are recursive if you write them like so: Say you want to determine the "value" of the "string" B4A3, which is in base 13. You know it's 3 + 13(A) + 13(13)(4) + 13(13)(13)(B) Another way to write that is: 0+3+13(A+13(4+13(B))) - and voila! Recursion.
Apart from the things already mentioned, I would suggest using the new-operator instead of free. The advantages of new are that it also does call constructors - which is irrelevant here since you're using a POD type, but important when it comes to objects such as std::string or your own custom classes - and that you can overload the new operator to suit your specific needs (which is irrelevant here, too :p). But don't go ahead using malloc for PODs and new for classes, since mixing them is considered bad style.
But okay, you got yourself some heap memory in from_dec... but where is it freed again? Basic rule: memory that you malloc (or calloc etc) must be passed to free at some point. The same rule applies to the new-operator, just that the release-operator is called delete. Note that for arrays, you need new[] and delete[]. DON'T ever allocate with new and release with delete[] or the other way around, since the memory won't be released correctly.
Nothing evil will happen when your toy program won't release the memory... I guess your PC has got enough RAM to cope with it and when you shut down your program, the OS releases the memory anyway.. but not all programs are (a) that tiny and (b) shut down often.
Also I'd avoid conio.h, since this is not portable. You're not using the most complicated IO, so the standard headers (iostream etc) should do.
Likewise, I think most programmers using modern languages follow the rule "Only use goto if other solutions are really crippled or tons of more work". This is a situation that can be easily solved by using loops, as shown by emceefly. In your program the goto is easy to handle, but you won't be writing such small programs forever, will you? ;)
I, for example, was presented with some legacy code recently.. 2000 lines of goto-littered code, yay! Trying to follow the code's logical flow was almost impossible ("Oh, jump ahead 200 lines, great... who needs context anyway"), even harder was to rewrite the damn thing.
So okay, your goto doesn't hurt here, but where's the benefit? 2-3 lines shorter? Doesn't really matter overall (if you're paid by lines of code, this could also be a major disadvantage ;)). Personally I find the loop version more readable and clean.
As you see, most of the points here can be ignored easily for your program, since it's a toy program. But when you think of larger programs, they make more sense (hopefully) ;)