Правильное форматирование чисел с ошибками (C ++) - PullRequest
1 голос
/ 06 июня 2009

У меня есть три набора чисел, измерение (которое находится в диапазоне 0-1 включительно), две ошибки (положительная и отрицательная. Эти числа должны отображаться последовательно с количеством значащих цифр, округленных в большую сторону, что соответствует первая ненулевая запись в любом из номеров.

Это требование пропускается при измерении, если оно одно (т. Е. Необходимо учитывать только цифры в ошибках). Например:

0.95637 (+0.00123, -0.02935) --> 0.96 +0.00 -0.03
1.00000 (+0.0, -0.0979) --> 1.0 +0.0 -0.1 (note had to truncate due to -ve error rounding up at first significant digit)

Теперь, получить первую ненулевую цифру легко, взяв log10 (num), но я испытываю идиотский момент, пытаясь заставить работать раздевание и округление без ошибок.

Все типы данных являются двойными, а язык выбора - C ++. Все и любые идеи приветствуются!

Ответы [ 5 ]

2 голосов
/ 06 июня 2009

Мой C ++ ржавый, но следующие не сделают:

std::string FormatNum(double measurement, double poserror, double negerror)
{
  int precision = 1;  // Precision to use if all numbers are zero

  if (poserror > 0)
    precision = ceil(-1 * log10(poserror));
  if (negerror < 0)
    precision = min(precision, ceil(-1 * log10(abs(negerror))));

  // If you meant the first non-zero in any of the 3 numbers, uncomment this:
  //if( measurement < 1 )
  //  precision = min(precision, ceil(-1 * log10(measurement)));

  stringstream ss;
  ss.setf(ios::fixed, ios::floatfield);
  ss.precision( precision );
  ss << measurement << " +" << poserror << " " << negerror ;
  return ss.str();
}
2 голосов
/ 06 июня 2009

Использование

cout.setf(ios::fixed, ios::floatfield);
cout.precision(2);

перед тем, как вы выводите числа, нужно сделать то, что вы ищете.

Редактировать: в качестве примера

double a = 0.95637;
double b = 0.00123;
double c = -0.02935;

cout.setf(ios::fixed, ios::floatfield);
cout.precision(2);
cout << a << endl;
cout << b << endl;
cout << c << endl;

выведет:

0.96
0.00
-0.03

Дальнейшее редактирование: вам, очевидно, придется отрегулировать точность, чтобы соответствовать значимым цифрам.

1 голос
/ 06 июня 2009

Может быть что-то вроде:

std::string FormatNum(double num)
{
  int numToDisplay ((int)((num + 0.005) * 100.0));
  stringstream ss;
  int digitsToDisplay(abs(numToDisplay) % 100);
  ss << ((num > 0) ? '+' : '-') << (abs(numToDisplay) / 100) << '.' << (digitsToDisplay / 10) << (digitsToDisplay % 10);
  return ss.str();
}

    stringstream ss;
    ss << FormatNum(0.95637) << ' ' << FormatNum(+0.00123) << ' ' << FormatNum(-0.02935);
0 голосов
/ 06 июня 2009

Вот вариант версии Шейн Пауэлл .

std::string FormatNum(double num, int decimals)
{
    stringstream ss;
    if (num >= 0.0)
        ss << '+';
    ss << setiosflags(ios::fixed) << setprecision(decimals) << num;
    return ss.str();
}
0 голосов
/ 06 июня 2009

Я не совсем уверен, как ваш log10 поможет вам получить первую ненулевую цифру, но, предположив, что это так (и, таким образом, вы знаете, до какой десятичной точки вы округляете), следующая функция будет округляться правильно:

double round(double num, int decimalPlaces)
{
    //given your example of .95637 being rounded to two decimal places
    double decimalMultiplier = pow(10, decimalPlaces); // = 100
    double roundedShiftedNum = num * decimalMultiplier + 0.5; // = 96.137
    double insignificantDigits = (roundedShiftedNum - (int)roundedShiftedNum; // = 0.137
    return (roundedShiftedNum - insignificantDigits) / decimalMultiplier; // = (96.137 - 0.137)/100 = 0.96
}

Возможно, это не самое элегантное решение, но я считаю, что оно работает (хотя и не пробовал)

...