Я пытаюсь оптимизировать решение проблемы, для которой требуется быстрое двойное сканирование. Я попытался реализовать функцию, которая считывала бы двойное число из стандартного ввода, но мне это не удалось. Может ли кто-нибудь указать мне простой код, который реализует это эффективно? Заранее спасибо.
Заметка Вот моя попытка, которая, кажется, имеет некоторые проблемы:
#include <stdio.h>
#include <stdlib.h>
inline double getDouble(FILE *f = stdin) {
char tmp[20], ch;
bool seen = false;
double sign = 1.0;
short index = 0;
while((ch = getc(stdin)) != EOF) {
if(ch == '-') {
sign = -1.0;
continue;
}
if(ch == ' ' || ch == '\n') {
if(seen) break;
} else {
seen = true;
tmp[index++] = ch;
}
}
return sign * (double)atof(tmp);
}
int main() {
int n;
scanf("%d", &n);
double *d = new double[n];
for(int i=0; i<n; ++i) {
d[i] = getDouble();
}
for(int i=0; i<n; ++i) {
printf("%.5lf\n", d[i]);
}
return 0;
}
Входные данные:
16
-2 -1 -4 -5
1 1 1 1
1.233 -435 -2.44
3
2 3 42 4
#include <stdio.h>
#include <stdlib.h>
inline double getDouble(FILE *f = stdin) {
double d;
scanf("%lf", &d);
return d;
}
int main() {
int n;
scanf("%d", &n);
double *d = new double[n];
for(int i=0; i<n; ++i) {
d[i] = getDouble();
}
for(int i=0; i<n; ++i) {
printf("%.5lf\n", d[i]);
}
return 0;
}
Изменить: Это действительно может быть немного быстрее, как это, я оцениваю следующее в 2-3 раза быстрее, он пройдет ваш вклад, но принимает довольно некоторые предположения, никаких гарантий за пределами тестового образца 🙂
inline double getDouble(FILE *f = stdin) {
char ch;
bool seen = false;
bool sign = false;
char values[10];
double result =0.;
bool beforeDot = true;
int beforeLength = 0;
double multiplier;
while((ch = getc(stdin)) != EOF) {
if(ch == '-') {
sign = true;
continue;
}
if(ch == ' ' || ch == '\n') {
if(seen) break;
continue;
}
if(ch == '.') {
beforeDot = false;
multiplier = 1.;
while(beforeLength) {
result += (double)(values[--beforeLength] - '0') * multiplier;
multiplier *= 10.;
}
multiplier = 10.;
}
else {
if(!beforeDot)
{
result += double(ch - '0') / multiplier;
multiplier *= 10.;
} else {
values[beforeLength++] = ch;
}
seen = true;
}
}
if(beforeDot) {
multiplier = 1;
while(beforeLength) {
result += (double)(values[--beforeLength] - '0') * multiplier;
multiplier *= 10.;
}
}
if(sign) result *= -1.;
return result;
}
Мой первый тест будет:
inline double getDouble(std::istream& in = std::cin)
{
double value;
if (!(in >> value)) {throw "Error";}
return value;
}
Если это не достаточно быстро (и только тогда), я бы попробовал:
inline double getDouble(FILE *f = stdin)
{
double value;
if ((scanf(f, "%e", &value) != 1) { throw "Error";}
return value;
}
Если это не достаточно быстро (и только тогда), я бы попробовал:
И я сомневаюсь, что это будет быстрее, чем scanf (), так как у людей было много времени, чтобы оптимизировать его
inline double getDouble(FILE *f = stdin)
{
int c;
// Ignore leading white space
while((c = getc(f) != EOF) && std::is_space(c)) {/*Loop*/}
// Only dealing with reals that look like this:
// [+|-]?[0-9]+(.[0-9]*)?
// or
// [+|-]?([0-9]*)?.[0-9]+
// Deal with sign
c=getc(f);
char sign = 1;
if ((c == '-') || (c == '+'))
{
if (c == '-') { sign = -1;}
c=getc(f);
}
int top
int bot;
// See if next character is a '.'
if (c == '.')
{
top = 0;
bot = readDigits(f, c, true);
}
else
{
top = readDigits(f, c, true);
bot = 0;
if (c == '.')
{
c = getc(f);
bot = readDigits(f, c, false);
}
}
//put back the last unused character
putc(c, f);
// calculate the result.
double result = sign * (top*1.0 + (bot*1.0/getSizeofBot(bot)));
return result;
}
int readDigits(FILE* f, int& c, bool digitRequired)
{
// c contains the first character.
// It should contain the last character read on exit.
// If digitRequired is true it is an exception to not
// find a digit, Other wise it is OK.
if ((digitRequired) && !std::is_digit(c))
{ throw "Error";
}
// Read an integer and return its value.
int value = 0;
while(std::is_digit(c))
{
value = value * 10 + (c - '0');
c = getc(f);
}
return value;
}