From 4d593a6149685e8b231d73a7ffc3ee974ef1f1bb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Wed, 25 Sep 2019 17:31:30 +0200 Subject: [PATCH] [poincare] PrintFloat: take into account the distinction between char and glyph length in ConvertFloatToText --- apps/graph/graph/graph_controller_helper.cpp | 2 +- .../graph/intersection_graph_controller.cpp | 2 +- apps/graph/graph/tangent_graph_controller.cpp | 6 +- apps/graph/list/list_parameter_controller.cpp | 19 ++-- apps/graph/values/values_controller.cpp | 7 +- .../hardware_test/battery_test_controller.cpp | 6 +- apps/probability/calculation_controller.cpp | 9 +- apps/regression/calculation_controller.cpp | 8 +- apps/regression/calculation_controller.h | 2 +- apps/regression/graph_controller.cpp | 4 +- apps/sequence/values/values_controller.cpp | 4 +- apps/shared/curve_view.cpp | 8 +- apps/shared/curve_view.h | 3 +- .../editable_cell_table_view_controller.cpp | 4 +- apps/shared/float_parameter_controller.cpp | 4 +- apps/shared/function_banner_delegate.cpp | 4 +- apps/shared/poincare_helpers.h | 7 +- apps/shared/sum_graph_controller.cpp | 16 ++-- apps/shared/sum_graph_controller.h | 2 +- apps/shared/values_controller.cpp | 2 +- apps/shared/xy_banner_view.h | 2 +- apps/solver/solutions_controller.cpp | 2 +- apps/statistics/box_controller.cpp | 4 +- apps/statistics/calculation_controller.cpp | 2 +- apps/statistics/calculation_controller.h | 2 +- apps/statistics/histogram_controller.cpp | 2 +- escher/include/escher/editable_text_cell.h | 2 +- .../message_table_cell_with_editable_text.h | 2 +- escher/src/editable_text_cell.cpp | 2 +- .../message_table_cell_with_editable_text.cpp | 2 +- ion/src/device/bench/command/adc.cpp | 3 +- poincare/include/poincare/print_float.h | 32 +++++-- poincare/src/float.cpp | 6 +- poincare/src/infinity.cpp | 2 +- poincare/src/integer.cpp | 4 +- poincare/src/print_float.cpp | 87 ++++++++++--------- poincare/test/print_float.cpp | 2 +- 37 files changed, 153 insertions(+), 124 deletions(-) diff --git a/apps/graph/graph/graph_controller_helper.cpp b/apps/graph/graph/graph_controller_helper.cpp index acfe76b2a..39e0b35d3 100644 --- a/apps/graph/graph/graph_controller_helper.cpp +++ b/apps/graph/graph/graph_controller_helper.cpp @@ -43,7 +43,7 @@ bool GraphControllerHelper::privateMoveCursorHorizontally(Shared::CurveViewCurso void GraphControllerHelper::reloadDerivativeInBannerViewForCursorOnFunction(Shared::CurveViewCursor * cursor, Ion::Storage::Record record) { ExpiringPointer function = App::app()->functionStore()->modelForRecord(record); - constexpr size_t bufferSize = FunctionBannerDelegate::k_maxNumberOfCharacters+PrintFloat::bufferSizeForFloatsWithPrecision(Preferences::LargeNumberOfSignificantDigits); + constexpr size_t bufferSize = FunctionBannerDelegate::k_maxNumberOfCharacters+PrintFloat::charSizeForFloatsWithPrecision(Preferences::LargeNumberOfSignificantDigits); char buffer[bufferSize]; const char * space = " "; int numberOfChar = function->derivativeNameWithArgument(buffer, bufferSize); diff --git a/apps/graph/graph/intersection_graph_controller.cpp b/apps/graph/graph/intersection_graph_controller.cpp index 1691e4239..dc520a3b5 100644 --- a/apps/graph/graph/intersection_graph_controller.cpp +++ b/apps/graph/graph/intersection_graph_controller.cpp @@ -18,7 +18,7 @@ const char * IntersectionGraphController::title() { void IntersectionGraphController::reloadBannerView() { CalculationGraphController::reloadBannerView(); - constexpr size_t bufferSize = FunctionBannerDelegate::k_maxNumberOfCharacters+Poincare::PrintFloat::bufferSizeForFloatsWithPrecision(Poincare::Preferences::LargeNumberOfSignificantDigits); + constexpr size_t bufferSize = FunctionBannerDelegate::k_maxNumberOfCharacters+Poincare::PrintFloat::charSizeForFloatsWithPrecision(Poincare::Preferences::LargeNumberOfSignificantDigits); char buffer[bufferSize]; const char * space = " "; const char * legend = "="; diff --git a/apps/graph/graph/tangent_graph_controller.cpp b/apps/graph/graph/tangent_graph_controller.cpp index 00db23d43..de88c4fe3 100644 --- a/apps/graph/graph/tangent_graph_controller.cpp +++ b/apps/graph/graph/tangent_graph_controller.cpp @@ -67,7 +67,7 @@ void TangentGraphController::reloadBannerView() { } FunctionBannerDelegate::reloadBannerViewForCursorOnFunction(m_cursor, m_record, Shared::FunctionApp::app()->functionStore(), AppsContainer::sharedAppsContainer()->globalContext()); GraphControllerHelper::reloadDerivativeInBannerViewForCursorOnFunction(m_cursor, m_record); - constexpr size_t bufferSize = FunctionBannerDelegate::k_maxNumberOfCharacters + PrintFloat::bufferSizeForFloatsWithPrecision(Preferences::LargeNumberOfSignificantDigits); + constexpr size_t bufferSize = FunctionBannerDelegate::k_maxNumberOfCharacters + PrintFloat::charSizeForFloatsWithPrecision(Preferences::LargeNumberOfSignificantDigits); char buffer[bufferSize]; Poincare::Context * context = textFieldDelegateApp()->localContext(); @@ -76,7 +76,7 @@ void TangentGraphController::reloadBannerView() { int legendLength = strlcpy(buffer, legend, bufferSize); ExpiringPointer function = App::app()->functionStore()->modelForRecord(m_record); double y = function->approximateDerivative(m_cursor->x(), context); - PoincareHelpers::ConvertFloatToText(y, buffer + legendLength, PrintFloat::bufferSizeForFloatsWithPrecision(precision), precision); + PoincareHelpers::ConvertFloatToText(y, buffer + legendLength, bufferSize - legendLength, precision); m_bannerView->aView()->setText(buffer); legend = "b="; @@ -84,7 +84,7 @@ void TangentGraphController::reloadBannerView() { Shared::TextFieldDelegateApp * myApp = textFieldDelegateApp(); assert(function->plotType() == Shared::ContinuousFunction::PlotType::Cartesian); y = -y*m_cursor->x()+function->evaluate2DAtParameter(m_cursor->x(), myApp->localContext()).x2(); - PoincareHelpers::ConvertFloatToText(y, buffer + legendLength, PrintFloat::bufferSizeForFloatsWithPrecision(precision), precision); + PoincareHelpers::ConvertFloatToText(y, buffer + legendLength, bufferSize - legendLength, precision); m_bannerView->bView()->setText(buffer); m_bannerView->reload(); } diff --git a/apps/graph/list/list_parameter_controller.cpp b/apps/graph/list/list_parameter_controller.cpp index f49df8484..331808e24 100644 --- a/apps/graph/list/list_parameter_controller.cpp +++ b/apps/graph/list/list_parameter_controller.cpp @@ -53,21 +53,22 @@ char intervalBracket(double value, bool opening) { return std::isinf(value) == opening ? ']' : '['; } -void writeInterval(char * buffer, int bufferSize, double min, double max, int numberOfSignificantDigits, Preferences::PrintFloatMode mode) { +int writeInterval(char * buffer, int bufferSize, double min, double max, int numberOfSignificantDigits, Preferences::PrintFloatMode mode) { int numberOfChar = 0; assert(bufferSize-1 > numberOfChar); buffer[numberOfChar++] = intervalBracket(min, true); - int sizeRequiredForFloat = PrintFloat::bufferSizeForFloatsWithPrecision(numberOfSignificantDigits); - assert(sizeRequiredForFloat < bufferSize - numberOfChar); - numberOfChar += PrintFloat::ConvertFloatToText(min, buffer+numberOfChar, sizeRequiredForFloat, numberOfSignificantDigits, mode); + int glyphLengthRequiredForFloat = PrintFloat::glyphLengthForFloatWithPrecision(numberOfSignificantDigits); + PrintFloat::TextLengths minLengths = PrintFloat::ConvertFloatToText(min, buffer+numberOfChar, bufferSize - numberOfChar, glyphLengthRequiredForFloat, numberOfSignificantDigits, mode); + numberOfChar += minLengths.CharLength; assert(bufferSize > numberOfChar); numberOfChar += strlcpy(buffer+numberOfChar, ",", bufferSize-numberOfChar); - assert(sizeRequiredForFloat < bufferSize - numberOfChar); - numberOfChar += PrintFloat::ConvertFloatToText(max, buffer+numberOfChar, sizeRequiredForFloat, numberOfSignificantDigits, mode); + PrintFloat::TextLengths maxLengths = PrintFloat::ConvertFloatToText(max, buffer+numberOfChar, bufferSize - numberOfChar, glyphLengthRequiredForFloat, numberOfSignificantDigits, mode); + numberOfChar += maxLengths.CharLength; assert(bufferSize-1 > numberOfChar); buffer[numberOfChar++] = intervalBracket(max, false); assert(bufferSize > numberOfChar); strlcpy(buffer+numberOfChar, " ", bufferSize-numberOfChar); + return minLengths.GlyphLength + maxLengths. GlyphLength + 3 + 1; // Count "[,] " glyphs } void ListParameterController::willDisplayCellForIndex(HighlightCell * cell, int index) { @@ -87,9 +88,9 @@ void ListParameterController::willDisplayCellForIndex(HighlightCell * cell, int double max = function->tMax(); constexpr int bufferSize = BufferTextView::k_maxNumberOfChar; char buffer[bufferSize]; - writeInterval(buffer, bufferSize, min, max, Preferences::VeryShortNumberOfSignificantDigits, Preferences::sharedPreferences()->displayMode()); - int numberOfAvailableChar = (m_functionDomain.bounds().width() - m_functionDomain.labelView()->bounds().width() - m_functionDomain.accessoryView()->bounds().width() - TableCell::k_labelMargin - TableCell::k_accessoryMargin)/KDFont::SmallFont->glyphSize().width(); - if (UTF8Helper::StringGlyphLength(buffer) > numberOfAvailableChar) { + int glyphLength = writeInterval(buffer, bufferSize, min, max, Preferences::VeryShortNumberOfSignificantDigits, Preferences::sharedPreferences()->displayMode()); + int numberOfAvailableGlyphs = (m_functionDomain.bounds().width() - m_functionDomain.labelView()->bounds().width() - m_functionDomain.accessoryView()->bounds().width() - TableCell::k_labelMargin - TableCell::k_accessoryMargin)/KDFont::SmallFont->glyphSize().width(); + if (glyphLength > numberOfAvailableGlyphs) { writeInterval(buffer, bufferSize, min, max, Preferences::VeryShortNumberOfSignificantDigits-1, Preferences::PrintFloatMode::Scientific); } m_functionDomain.setAccessoryText(buffer); diff --git a/apps/graph/values/values_controller.cpp b/apps/graph/values/values_controller.cpp index 6f729af42..1520f1b68 100644 --- a/apps/graph/values/values_controller.cpp +++ b/apps/graph/values/values_controller.cpp @@ -248,17 +248,14 @@ void ValuesController::printEvaluationOfAbscissaAtColumn(double abscissa, int co } } int numberOfChar = 0; - const int floatBufferSize = PrintFloat::bufferSizeForFloatsWithPrecision(Preferences::LargeNumberOfSignificantDigits); if (isParametric) { assert(numberOfChar < bufferSize-1); buffer[numberOfChar++] = '('; - assert(floatBufferSize <= bufferSize-numberOfChar); - numberOfChar += PoincareHelpers::ConvertFloatToText(evaluationX, buffer+numberOfChar, floatBufferSize, Preferences::LargeNumberOfSignificantDigits); + numberOfChar += PoincareHelpers::ConvertFloatToText(evaluationX, buffer+numberOfChar, bufferSize - numberOfChar, Preferences::LargeNumberOfSignificantDigits); assert(numberOfChar < bufferSize-1); buffer[numberOfChar++] = ';'; } - assert(floatBufferSize <= bufferSize-numberOfChar); - numberOfChar += PoincareHelpers::ConvertFloatToText(evaluationY, buffer+numberOfChar, floatBufferSize, Preferences::LargeNumberOfSignificantDigits); + numberOfChar += PoincareHelpers::ConvertFloatToText(evaluationY, buffer+numberOfChar, bufferSize - numberOfChar, Preferences::LargeNumberOfSignificantDigits); if (isParametric) { assert(numberOfChar+1 < bufferSize-1); buffer[numberOfChar++] = ')'; diff --git a/apps/hardware_test/battery_test_controller.cpp b/apps/hardware_test/battery_test_controller.cpp index 70d406784..997a99ea1 100644 --- a/apps/hardware_test/battery_test_controller.cpp +++ b/apps/hardware_test/battery_test_controller.cpp @@ -1,6 +1,7 @@ #include "battery_test_controller.h" #include #include "app.h" +#include extern "C" { #include } @@ -8,6 +9,7 @@ extern "C" { #include using namespace Poincare; +using namespace Shared; namespace HardwareTest { @@ -43,12 +45,12 @@ void BatteryTestController::viewWillAppear() { void BatteryTestController::updateBatteryState(float batteryLevel, bool batteryCharging) { constexpr int precision = Preferences::LargeNumberOfSignificantDigits; - constexpr int sizeForPrecision = PrintFloat::bufferSizeForFloatsWithPrecision(precision); + constexpr int sizeForPrecision = PrintFloat::charSizeForFloatsWithPrecision(precision); constexpr size_t bufferLevelSize = ContentView::k_maxNumberOfCharacters + sizeForPrecision; char bufferLevel[bufferLevelSize]; const char * legend = "Battery level: "; int legendLength = strlcpy(bufferLevel, legend, bufferLevelSize); - PrintFloat::ConvertFloatToText(batteryLevel, bufferLevel+legendLength, sizeForPrecision, precision, Preferences::PrintFloatMode::Decimal); + PoincareHelpers::ConvertFloatToTextWithDisplayMode(batteryLevel, bufferLevel+legendLength, sizeForPrecision, precision, Preferences::PrintFloatMode::Decimal); m_view.batteryLevelTextView()->setText(bufferLevel); constexpr size_t bufferChargingSize = ContentView::k_maxNumberOfCharacters + sizeForPrecision; diff --git a/apps/probability/calculation_controller.cpp b/apps/probability/calculation_controller.cpp index a455c4692..1c2a1b097 100644 --- a/apps/probability/calculation_controller.cpp +++ b/apps/probability/calculation_controller.cpp @@ -180,9 +180,10 @@ void CalculationController::willDisplayCellAtLocation(HighlightCell * cell, int return; } constexpr int precision = Preferences::LargeNumberOfSignificantDigits; - constexpr int bufferSize = PrintFloat::bufferSizeForFloatsWithPrecision(precision); + constexpr int bufferSize = PrintFloat::charSizeForFloatsWithPrecision(precision); char buffer[bufferSize]; - PrintFloat::ConvertFloatToText(m_calculation->parameterAtIndex(i-1), buffer, bufferSize, precision, Preferences::PrintFloatMode::Decimal); + // FIXME: Leo has not decided yet if we should use the prefered mode instead of always using scientific mode + PoincareHelpers::ConvertFloatToTextWithDisplayMode(m_calculation->parameterAtIndex(i-1), buffer, bufferSize, precision, Preferences::PrintFloatMode::Decimal); field->setText(buffer); } } @@ -283,9 +284,9 @@ void CalculationController::updateTitle() { break; } constexpr int precision = Preferences::ShortNumberOfSignificantDigits; - constexpr size_t bufferSize = PrintFloat::bufferSizeForFloatsWithPrecision(precision); + constexpr int bufferSize = PrintFloat::charSizeForFloatsWithPrecision(precision); char buffer[bufferSize]; - PrintFloat::ConvertFloatToText(m_distribution->parameterValueAtIndex(index), buffer, bufferSize, precision, Preferences::PrintFloatMode::Decimal); + PoincareHelpers::ConvertFloatToTextWithDisplayMode(m_distribution->parameterValueAtIndex(index), buffer, bufferSize, precision, Preferences::PrintFloatMode::Decimal); currentChar += strlcpy(m_titleBuffer+currentChar, buffer, k_titleBufferSize - currentChar); if (currentChar >= k_titleBufferSize) { break; diff --git a/apps/regression/calculation_controller.cpp b/apps/regression/calculation_controller.cpp index b348f1aa3..021760dc2 100644 --- a/apps/regression/calculation_controller.cpp +++ b/apps/regression/calculation_controller.cpp @@ -179,7 +179,7 @@ void CalculationController::willDisplayCellAtLocation(HighlightCell * cell, int double calculation1 = (m_store->*calculationMethods[j-1])(seriesNumber, 0); double calculation2 = (m_store->*calculationMethods[j-1])(seriesNumber, 1); EvenOddDoubleBufferTextCellWithSeparator * myCell = (EvenOddDoubleBufferTextCellWithSeparator *)cell; - constexpr int bufferSize = PrintFloat::bufferSizeForFloatsWithPrecision(numberSignificantDigits); + constexpr int bufferSize = PrintFloat::charSizeForFloatsWithPrecision(numberSignificantDigits); char buffer[bufferSize]; PoincareHelpers::ConvertFloatToText(calculation1, buffer, bufferSize, numberSignificantDigits); myCell->setFirstText(buffer); @@ -198,7 +198,7 @@ void CalculationController::willDisplayCellAtLocation(HighlightCell * cell, int assert(j != k_regressionCellIndex); CalculPointer calculationMethods[] = {&Store::doubleCastedNumberOfPairsOfSeries, &Store::covariance, &Store::columnProductSum}; double calculation = (m_store->*calculationMethods[j-k_totalNumberOfDoubleBufferRows-1])(seriesNumber); - constexpr int bufferSize = PrintFloat::bufferSizeForFloatsWithPrecision(numberSignificantDigits); + constexpr int bufferSize = PrintFloat::charSizeForFloatsWithPrecision(numberSignificantDigits); char buffer[bufferSize]; PoincareHelpers::ConvertFloatToText(calculation, buffer, bufferSize, numberSignificantDigits); bufferCell->setText(buffer); @@ -230,7 +230,7 @@ void CalculationController::willDisplayCellAtLocation(HighlightCell * cell, int if (modelType == Model::Type::Linear) { CalculPointer calculationMethods[2] = {&Store::correlationCoefficient, &Store::squaredCorrelationCoefficient}; double calculation = (m_store->*calculationMethods[j - k_regressionCellIndex - maxNumberCoefficients - 1])(seriesNumber); - constexpr int bufferSize = PrintFloat::bufferSizeForFloatsWithPrecision(numberSignificantDigits); + constexpr int bufferSize = PrintFloat::charSizeForFloatsWithPrecision(numberSignificantDigits); char buffer[bufferSize]; PoincareHelpers::ConvertFloatToText(calculation, buffer, bufferSize, numberSignificantDigits); bufferCell->setText(buffer); @@ -246,7 +246,7 @@ void CalculationController::willDisplayCellAtLocation(HighlightCell * cell, int bufferCell->setText(I18n::translate(I18n::Message::Dash)); return; } else { - constexpr int bufferSize = PrintFloat::bufferSizeForFloatsWithPrecision(numberSignificantDigits); + constexpr int bufferSize = PrintFloat::charSizeForFloatsWithPrecision(numberSignificantDigits); char buffer[bufferSize]; PoincareHelpers::ConvertFloatToText(coefficients[j - k_regressionCellIndex - 1], buffer, bufferSize, numberSignificantDigits); bufferCell->setText(buffer); diff --git a/apps/regression/calculation_controller.h b/apps/regression/calculation_controller.h index 349b25bc7..b203d07ec 100644 --- a/apps/regression/calculation_controller.h +++ b/apps/regression/calculation_controller.h @@ -63,7 +63,7 @@ private: static constexpr KDCoordinate k_cellHeight = 25; static constexpr KDCoordinate k_titleCalculationCellWidth = Ion::Display::Width/2 - Metric::CommonRightMargin/2 - Metric::CommonLeftMargin/2; // TODO: change 7 for KDFont::SmallFont->glyphSize().width() - static constexpr KDCoordinate k_minCalculationCellWidth = 7*2*(Poincare::PrintFloat::bufferSizeForFloatsWithPrecision(Poincare::Preferences::LargeNumberOfSignificantDigits)); //Calculation width should at least be able to hold to numbers with LargeNumberOfSignificantDigits. + static constexpr KDCoordinate k_minCalculationCellWidth = 7*2*(Poincare::PrintFloat::glyphLengthForFloatWithPrecision(Poincare::Preferences::LargeNumberOfSignificantDigits)); //Calculation width should at least be able to hold to numbers with LargeNumberOfSignificantDigits. static constexpr KDCoordinate k_cubicCalculationCellWidth = maxCoordinate(150, k_minCalculationCellWidth); // Should hold aX^3+bX^2+cX+d static constexpr KDCoordinate k_quarticCalculationCellWidth = maxCoordinate(195, k_minCalculationCellWidth ); // Should hold ? aX^4+bX^3+c*X^2+dX+e static constexpr KDCoordinate k_margin = 8; diff --git a/apps/regression/graph_controller.cpp b/apps/regression/graph_controller.cpp index 0be8e1631..173254d6c 100644 --- a/apps/regression/graph_controller.cpp +++ b/apps/regression/graph_controller.cpp @@ -105,7 +105,7 @@ Poincare::Context * GraphController::globalContext() { void GraphController::reloadBannerView() { // Set point equals: "P(...) =" - constexpr size_t bufferSize = k_maxNumberOfCharacters + PrintFloat::bufferSizeForFloatsWithPrecision(Preferences::LargeNumberOfSignificantDigits); + constexpr size_t bufferSize = k_maxNumberOfCharacters + PrintFloat::charSizeForFloatsWithPrecision(Preferences::LargeNumberOfSignificantDigits); char buffer[bufferSize]; int numberOfChar = 0; const char * legend = " P("; @@ -119,7 +119,7 @@ void GraphController::reloadBannerView() { assert(numberOfChar <= bufferSize); numberOfChar += strlcpy(buffer + numberOfChar, legend, bufferSize - numberOfChar); } else { - numberOfChar += PrintFloat::ConvertFloatToText(std::round((float)*m_selectedDotIndex+1.0f), buffer + numberOfChar, bufferSize - numberOfChar, Preferences::ShortNumberOfSignificantDigits, Preferences::PrintFloatMode::Decimal); + numberOfChar += PoincareHelpers::ConvertFloatToTextWithDisplayMode(std::round((float)*m_selectedDotIndex+1.0f), buffer + numberOfChar, bufferSize - numberOfChar, Preferences::ShortNumberOfSignificantDigits, Preferences::PrintFloatMode::Decimal); } legend = ") "; assert(numberOfChar <= bufferSize); diff --git a/apps/sequence/values/values_controller.cpp b/apps/sequence/values/values_controller.cpp index 847ff2363..43d99f029 100644 --- a/apps/sequence/values/values_controller.cpp +++ b/apps/sequence/values/values_controller.cpp @@ -73,9 +73,7 @@ bool ValuesController::setDataAtLocation(double floatBody, int columnIndex, int void ValuesController::printEvaluationOfAbscissaAtColumn(double abscissa, int columnIndex, char * buffer, const int bufferSize) { Shared::ExpiringPointer sequence = functionStore()->modelForRecord(recordAtColumn(columnIndex)); Coordinate2D xy = sequence->evaluateXYAtParameter(abscissa, textFieldDelegateApp()->localContext()); - const int floatBufferSize = PrintFloat::bufferSizeForFloatsWithPrecision(Preferences::LargeNumberOfSignificantDigits); - assert(floatBufferSize <= bufferSize); - Shared::PoincareHelpers::ConvertFloatToText(xy.x2(), buffer, floatBufferSize, Preferences::LargeNumberOfSignificantDigits); + Shared::PoincareHelpers::ConvertFloatToText(xy.x2(), buffer, bufferSize, Preferences::LargeNumberOfSignificantDigits); } Shared::Interval * ValuesController::intervalAtColumn(int columnIndex) { diff --git a/apps/shared/curve_view.cpp b/apps/shared/curve_view.cpp index 19e33a857..53f1d9b32 100644 --- a/apps/shared/curve_view.cpp +++ b/apps/shared/curve_view.cpp @@ -177,10 +177,10 @@ void CurveView::computeLabels(Axis axis) { float labelValue = labelValueAtIndex(axis, i); /* Label cannot hold more than k_labelBufferMaxSize characters to prevent * them from overprinting one another.*/ - int labelMaxSize = k_labelBufferMaxSize; + int labelMaxGlyphLength = k_labelBufferMaxGlyphLength; if (axis == Axis::Horizontal) { float pixelsPerLabel = maxFloat(0.0f, ((float)Ion::Display::Width)/((float)axisLabelsCount) - k_labelMargin); - labelMaxSize = minInt(k_labelBufferMaxSize, pixelsPerLabel/k_font->glyphSize().width()+1); + labelMaxGlyphLength = minInt(k_labelBufferMaxGlyphLength, pixelsPerLabel/k_font->glyphSize().width()); } if (labelValue < step && labelValue > -step) { @@ -195,7 +195,8 @@ void CurveView::computeLabels(Axis axis) { PrintFloat::ConvertFloatToText( labelValue, labelBuffer, - labelMaxSize, + k_labelBufferMaxSize, + labelMaxGlyphLength, k_numberSignificantDigits, Preferences::PrintFloatMode::Decimal); @@ -825,6 +826,7 @@ void CurveView::computeHorizontalExtremaLabels(bool increaseNumberOfSignificantD labelValueAtIndex(axis, i), label(axis, i), k_labelBufferMaxSize, + k_labelBufferMaxGlyphLength, increaseNumberOfSignificantDigits ? k_bigNumberSignificantDigits : k_numberSignificantDigits, Preferences::PrintFloatMode::Decimal); } diff --git a/apps/shared/curve_view.h b/apps/shared/curve_view.h index 71a4a2b74..1c4ac72b8 100644 --- a/apps/shared/curve_view.h +++ b/apps/shared/curve_view.h @@ -50,7 +50,8 @@ protected: constexpr static KDCoordinate k_labelGraduationLength = 6; constexpr static int k_numberSignificantDigits = 6; constexpr static int k_bigNumberSignificantDigits = Poincare::Preferences::LargeNumberOfSignificantDigits; - constexpr static int k_labelBufferMaxSize = 1 + k_bigNumberSignificantDigits + 3 + 3 + 1; // '-' + significant digits + '.' + "E-" + 3 digits + null-terminating char + constexpr static int k_labelBufferMaxSize = 1 + k_bigNumberSignificantDigits + 1 + Poincare::PrintFloat::k_specialECodePointByteLength + 1 + 3 + 1; // '-' + significant digits + '.' + "E" + '-' + 3 digits + null-terminating char + constexpr static int k_labelBufferMaxGlyphLength = 1 + k_bigNumberSignificantDigits + 3 + 3; // '-' + significant digits + ".E-" + 3 digits constexpr static int k_maxNumberOfXLabels = CurveViewRange::k_maxNumberOfXGridUnits; constexpr static int k_maxNumberOfYLabels = CurveViewRange::k_maxNumberOfYGridUnits; constexpr static int k_externRectMargin = 2; diff --git a/apps/shared/editable_cell_table_view_controller.cpp b/apps/shared/editable_cell_table_view_controller.cpp index 2441a4334..36657c8de 100644 --- a/apps/shared/editable_cell_table_view_controller.cpp +++ b/apps/shared/editable_cell_table_view_controller.cpp @@ -78,7 +78,7 @@ void EditableCellTableViewController::willDisplayCellAtLocationWithDisplayMode(H if (cellAtLocationIsEditable(i, j)) { EvenOddEditableTextCell * myEditableValueCell = (EvenOddEditableTextCell *)cell; assert(!myEditableValueCell->editableTextCell()->textField()->isEditing()); - const int bufferSize = PrintFloat::bufferSizeForFloatsWithPrecision(Preferences::LargeNumberOfSignificantDigits); + const int bufferSize = PrintFloat::charSizeForFloatsWithPrecision(Preferences::LargeNumberOfSignificantDigits); char buffer[bufferSize]; // Special case 1: last row if (j == numberOfElementsInColumn(i) + 1) { @@ -86,7 +86,7 @@ void EditableCellTableViewController::willDisplayCellAtLocationWithDisplayMode(H * data */ buffer[0] = 0; } else { - PrintFloat::ConvertFloatToText(dataAtLocation(i, j), buffer, bufferSize, Preferences::LargeNumberOfSignificantDigits, floatDisplayMode); + PoincareHelpers::ConvertFloatToTextWithDisplayMode(dataAtLocation(i, j), buffer, bufferSize, Preferences::LargeNumberOfSignificantDigits, floatDisplayMode); } myEditableValueCell->editableTextCell()->textField()->setText(buffer); } diff --git a/apps/shared/float_parameter_controller.cpp b/apps/shared/float_parameter_controller.cpp index 4ddeac476..685d7f0ff 100644 --- a/apps/shared/float_parameter_controller.cpp +++ b/apps/shared/float_parameter_controller.cpp @@ -121,9 +121,9 @@ void FloatParameterController::willDisplayCellForIndex(HighlightCell * cell, return; } constexpr int precision = Preferences::LargeNumberOfSignificantDigits; - constexpr int bufferSize = PrintFloat::bufferSizeForFloatsWithPrecision(precision); + constexpr int bufferSize = PrintFloat::charSizeForFloatsWithPrecision(precision); char buffer[bufferSize]; - PrintFloat::ConvertFloatToText(parameterAtIndex(index), buffer, bufferSize, precision, Preferences::PrintFloatMode::Decimal); + PoincareHelpers::ConvertFloatToTextWithDisplayMode(parameterAtIndex(index), buffer, bufferSize, precision, Preferences::PrintFloatMode::Decimal); myCell->setAccessoryText(buffer); } diff --git a/apps/shared/function_banner_delegate.cpp b/apps/shared/function_banner_delegate.cpp index 98d98eecf..87e0f953b 100644 --- a/apps/shared/function_banner_delegate.cpp +++ b/apps/shared/function_banner_delegate.cpp @@ -9,7 +9,7 @@ namespace Shared { void FunctionBannerDelegate::reloadBannerViewForCursorOnFunction(CurveViewCursor * cursor, Ion::Storage::Record record, FunctionStore * functionStore, Poincare::Context * context) { ExpiringPointer function = functionStore->modelForRecord(record); - constexpr int bufferSize = k_maxNumberOfCharacters+PrintFloat::bufferSizeForFloatsWithPrecision(Preferences::LargeNumberOfSignificantDigits); + constexpr int bufferSize = k_maxNumberOfCharacters+PrintFloat::charSizeForFloatsWithPrecision(Preferences::LargeNumberOfSignificantDigits); char buffer[bufferSize]; const char * space = " "; int numberOfChar = 0; @@ -20,7 +20,7 @@ void FunctionBannerDelegate::reloadBannerViewForCursorOnFunction(CurveViewCursor constexpr int precision = Preferences::MediumNumberOfSignificantDigits; - numberOfChar = PoincareHelpers::ConvertFloatToText(cursor->t(), buffer, PrintFloat::bufferSizeForFloatsWithPrecision(precision), precision); + numberOfChar = PoincareHelpers::ConvertFloatToText(cursor->t(), buffer, bufferSize, precision); assert(numberOfChar <= bufferSize); strlcpy(buffer+numberOfChar, space, bufferSize - numberOfChar); bannerView()->abscissaValue()->setText(buffer); diff --git a/apps/shared/poincare_helpers.h b/apps/shared/poincare_helpers.h index 6d6407436..b8d73f340 100644 --- a/apps/shared/poincare_helpers.h +++ b/apps/shared/poincare_helpers.h @@ -16,7 +16,12 @@ inline Poincare::Layout CreateLayout(const Poincare::Expression e) { template inline int ConvertFloatToText(T d, char * buffer, int bufferSize, int numberOfSignificantDigits) { - return Poincare::PrintFloat::ConvertFloatToText(d, buffer, bufferSize, numberOfSignificantDigits, Poincare::Preferences::sharedPreferences()->displayMode()); + return Poincare::PrintFloat::ConvertFloatToText(d, buffer, bufferSize, Poincare::PrintFloat::glyphLengthForFloatWithPrecision(numberOfSignificantDigits), numberOfSignificantDigits, Poincare::Preferences::sharedPreferences()->displayMode()).CharLength; +} + +template +inline int ConvertFloatToTextWithDisplayMode(T d, char * buffer, int bufferSize, int numberOfSignificantDigits, Poincare::Preferences::PrintFloatMode displayMode) { + return Poincare::PrintFloat::ConvertFloatToText(d, buffer, bufferSize, Poincare::PrintFloat::glyphLengthForFloatWithPrecision(numberOfSignificantDigits), numberOfSignificantDigits, displayMode).CharLength; } inline int Serialize(const Poincare::Expression e, char * buffer, int bufferSize, int numberOfSignificantDigits = Poincare::PrintFloat::k_numberOfStoredSignificantDigits) { diff --git a/apps/shared/sum_graph_controller.cpp b/apps/shared/sum_graph_controller.cpp index 0a204cf8a..babf74e0e 100644 --- a/apps/shared/sum_graph_controller.cpp +++ b/apps/shared/sum_graph_controller.cpp @@ -179,9 +179,9 @@ void SumGraphController::LegendView::setLegendMessage(I18n::Message message, Ste void SumGraphController::LegendView::setEditableZone(double d) { constexpr int precision = Preferences::MediumNumberOfSignificantDigits; - constexpr int bufferSize = PrintFloat::bufferSizeForFloatsWithPrecision(precision); + constexpr int bufferSize = PrintFloat::charSizeForFloatsWithPrecision(precision); char buffer[bufferSize]; - PrintFloat::ConvertFloatToText(d, buffer, bufferSize, precision, Preferences::PrintFloatMode::Decimal); + PoincareHelpers::ConvertFloatToTextWithDisplayMode(d, buffer, bufferSize, precision, Preferences::PrintFloatMode::Decimal); m_editableZone.setText(buffer); } @@ -193,28 +193,28 @@ void SumGraphController::LegendView::setSumSymbol(Step step, double start, doubl m_sumLayout = LayoutHelper::CodePointString(sigma, sigmaLength); } else if (step == Step::SecondParameter) { constexpr int precision = Preferences::MediumNumberOfSignificantDigits; - constexpr int bufferSize = PrintFloat::bufferSizeForFloatsWithPrecision(precision); + constexpr int bufferSize = PrintFloat::charSizeForFloatsWithPrecision(precision); char buffer[bufferSize]; - PrintFloat::ConvertFloatToText(start, buffer, bufferSize, precision, Preferences::PrintFloatMode::Decimal); + PoincareHelpers::ConvertFloatToTextWithDisplayMode(start, buffer, bufferSize, precision, Preferences::PrintFloatMode::Decimal); m_sumLayout = CondensedSumLayout::Builder( LayoutHelper::CodePointString(sigma, sigmaLength), LayoutHelper::String(buffer, strlen(buffer), k_font), EmptyLayout::Builder(EmptyLayoutNode::Color::Yellow, false, k_font, false)); } else { constexpr int precision = Preferences::LargeNumberOfSignificantDigits; - constexpr int sizeForPrecision = PrintFloat::bufferSizeForFloatsWithPrecision(precision); + constexpr int sizeForPrecision = PrintFloat::charSizeForFloatsWithPrecision(precision); constexpr int bufferSize = 2 + sizeForPrecision; char buffer[bufferSize]; - PrintFloat::ConvertFloatToText(start, buffer, sizeForPrecision, precision, Preferences::PrintFloatMode::Decimal); + PoincareHelpers::ConvertFloatToTextWithDisplayMode(start, buffer, bufferSize, precision, Preferences::PrintFloatMode::Decimal); Layout start = LayoutHelper::String(buffer, strlen(buffer), k_font); - PrintFloat::ConvertFloatToText(end, buffer, sizeForPrecision, precision, Preferences::PrintFloatMode::Decimal); + PoincareHelpers::ConvertFloatToTextWithDisplayMode(end, buffer, bufferSize, precision, Preferences::PrintFloatMode::Decimal); Layout end = LayoutHelper::String(buffer, strlen(buffer), k_font); m_sumLayout = CondensedSumLayout::Builder( LayoutHelper::CodePointString(sigma, sigmaLength), start, end); strlcpy(buffer, "= ", 3); - PoincareHelpers::ConvertFloatToText(result, buffer+2, sizeForPrecision, precision); + PoincareHelpers::ConvertFloatToText(result, buffer+2, bufferSize-2, precision); m_sumLayout = HorizontalLayout::Builder( m_sumLayout, functionLayout, diff --git a/apps/shared/sum_graph_controller.h b/apps/shared/sum_graph_controller.h index 6a7ba1b86..0915616a5 100644 --- a/apps/shared/sum_graph_controller.h +++ b/apps/shared/sum_graph_controller.h @@ -56,7 +56,7 @@ private: void setEditableZone(double d); void setSumSymbol(Step step, double start, double end, double result, Poincare::Layout functionLayout); private: - constexpr static KDCoordinate k_editableZoneBufferSize = Poincare::PrintFloat::k_maxFloatBufferSize; + constexpr static KDCoordinate k_editableZoneBufferSize = Poincare::PrintFloat::k_maxFloatCharSize; constexpr static KDCoordinate k_legendHeight = 35; constexpr static const KDFont * k_font = KDFont::SmallFont; static KDCoordinate editableZoneWidth() { return 12*k_font->glyphSize().width(); } diff --git a/apps/shared/values_controller.cpp b/apps/shared/values_controller.cpp index 3427462c4..ad167915b 100644 --- a/apps/shared/values_controller.cpp +++ b/apps/shared/values_controller.cpp @@ -124,7 +124,7 @@ void ValuesController::willDisplayCellAtLocation(HighlightCell * cell, int i, in willDisplayCellAtLocationWithDisplayMode(cell, i, j, Preferences::sharedPreferences()->displayMode()); // The cell is not a title cell and not editable if (typeAtLocation(i,j) == k_notEditableValueCellType) { - constexpr int bufferSize = 2*PrintFloat::bufferSizeForFloatsWithPrecision(Preferences::LargeNumberOfSignificantDigits)+3; + constexpr int bufferSize = 2*PrintFloat::charSizeForFloatsWithPrecision(Preferences::LargeNumberOfSignificantDigits)+3; char buffer[bufferSize]; // The largest buffer holds (-1.234567E-123;-1.234567E-123) // Special case: last row if (j == numberOfElementsInColumn(i) + 1) { diff --git a/apps/shared/xy_banner_view.h b/apps/shared/xy_banner_view.h index f5f16c642..c1b6c0e70 100644 --- a/apps/shared/xy_banner_view.h +++ b/apps/shared/xy_banner_view.h @@ -20,7 +20,7 @@ public: protected: View * subviewAtIndex(int index) override; private: - constexpr static KDCoordinate k_abscissaBufferSize = Poincare::PrintFloat::k_maxFloatBufferSize; + constexpr static KDCoordinate k_abscissaBufferSize = Poincare::PrintFloat::k_maxFloatCharSize; int numberOfSubviews() const override { return k_numberOfSubviews; } BufferTextView m_abscissaSymbol; TextField m_abscissaValue; diff --git a/apps/solver/solutions_controller.cpp b/apps/solver/solutions_controller.cpp index 8ec20a4a5..db0657eeb 100644 --- a/apps/solver/solutions_controller.cpp +++ b/apps/solver/solutions_controller.cpp @@ -189,7 +189,7 @@ void SolutionsController::willDisplayCellAtLocation(HighlightCell * cell, int i, if (m_equationStore->type() == EquationStore::Type::Monovariable) { EvenOddBufferTextCell * valueCell = static_cast(cell); constexpr int precision = Preferences::LargeNumberOfSignificantDigits; - constexpr int bufferSize = PrintFloat::bufferSizeForFloatsWithPrecision(precision); + constexpr int bufferSize = PrintFloat::charSizeForFloatsWithPrecision(precision); char bufferValue[bufferSize]; PoincareHelpers::ConvertFloatToText(m_equationStore->approximateSolutionAtIndex(j), bufferValue, bufferSize, precision); valueCell->setText(bufferValue); diff --git a/apps/statistics/box_controller.cpp b/apps/statistics/box_controller.cpp index 85158b3b8..406724b78 100644 --- a/apps/statistics/box_controller.cpp +++ b/apps/statistics/box_controller.cpp @@ -51,12 +51,12 @@ void BoxController::reloadBannerView() { // Set calculation result assert(UTF8Decoder::CharSizeOfCodePoint(' ') == 1); constexpr int precision = Preferences::LargeNumberOfSignificantDigits; - constexpr int bufferSize = PrintFloat::bufferSizeForFloatsWithPrecision(precision) + 1; + constexpr int bufferSize = PrintFloat::charSizeForFloatsWithPrecision(precision) + 1; char buffer[bufferSize]; CalculPointer calculationMethods[5] = {&Store::minValue, &Store::firstQuartile, &Store::median, &Store::thirdQuartile, &Store::maxValue}; double calculation = (m_store->*calculationMethods[selectedQuantile])(selectedSeriesIndex()); - int numberOfChar = PoincareHelpers::ConvertFloatToText(calculation, buffer, bufferSize - 1, precision); + int numberOfChar = PoincareHelpers::ConvertFloatToText(calculation, buffer, bufferSize, precision); buffer[numberOfChar++] = ' '; assert(numberOfChar <= bufferSize - 1); buffer[numberOfChar] = 0; diff --git a/apps/statistics/calculation_controller.cpp b/apps/statistics/calculation_controller.cpp index 8aeacd7ba..de553cf1b 100644 --- a/apps/statistics/calculation_controller.cpp +++ b/apps/statistics/calculation_controller.cpp @@ -100,7 +100,7 @@ void CalculationController::willDisplayCellAtLocation(HighlightCell * cell, int double calculation = (m_store->*calculationMethods[j-1])(seriesIndex); EvenOddBufferTextCell * calculationCell = static_cast(cell); constexpr int precision = Preferences::LargeNumberOfSignificantDigits; - constexpr int bufferSize = PrintFloat::bufferSizeForFloatsWithPrecision(precision); + constexpr int bufferSize = PrintFloat::charSizeForFloatsWithPrecision(precision); char buffer[bufferSize]; PoincareHelpers::ConvertFloatToText(calculation, buffer, bufferSize, precision); calculationCell->setText(buffer); diff --git a/apps/statistics/calculation_controller.h b/apps/statistics/calculation_controller.h index 1c568bcdf..e7d508e4f 100644 --- a/apps/statistics/calculation_controller.h +++ b/apps/statistics/calculation_controller.h @@ -55,7 +55,7 @@ private: static constexpr KDCoordinate k_cellHeight = 20; static constexpr KDCoordinate k_calculationTitleCellWidth = 175; // TODO: change 7 for KDFont::SmallFont->glyphSize().width() - static constexpr KDCoordinate k_calculationCellWidth = 7*(Poincare::PrintFloat::bufferSizeForFloatsWithPrecision(Poincare::Preferences::LargeNumberOfSignificantDigits)); + static constexpr KDCoordinate k_calculationCellWidth = 7*(Poincare::PrintFloat::glyphLengthForFloatWithPrecision(Poincare::Preferences::LargeNumberOfSignificantDigits)); static constexpr KDCoordinate k_margin = 8; static constexpr KDCoordinate k_scrollBarMargin = Metric::CommonRightMargin; diff --git a/apps/statistics/histogram_controller.cpp b/apps/statistics/histogram_controller.cpp index 2d1ca5962..d92671801 100644 --- a/apps/statistics/histogram_controller.cpp +++ b/apps/statistics/histogram_controller.cpp @@ -96,7 +96,7 @@ void HistogramController::reloadBannerView() { return; } constexpr int precision = Preferences::LargeNumberOfSignificantDigits; - constexpr size_t bufferSize = k_maxNumberOfCharacters + 2 * PrintFloat::bufferSizeForFloatsWithPrecision(precision); + constexpr size_t bufferSize = k_maxNumberOfCharacters + 2 * PrintFloat::charSizeForFloatsWithPrecision(precision); char buffer[bufferSize] = ""; int numberOfChar = 0; diff --git a/escher/include/escher/editable_text_cell.h b/escher/include/escher/editable_text_cell.h index 438ee6e49..d2e4df5ee 100644 --- a/escher/include/escher/editable_text_cell.h +++ b/escher/include/escher/editable_text_cell.h @@ -32,7 +32,7 @@ public: private: constexpr static KDCoordinate k_separatorThickness = Metric::CellSeparatorThickness; TextField m_textField; - char m_textBody[Poincare::PrintFloat::k_maxFloatBufferSize]; + char m_textBody[Poincare::PrintFloat::k_maxFloatCharSize]; KDCoordinate m_topMargin; KDCoordinate m_rightMargin; KDCoordinate m_bottomMargin; diff --git a/escher/include/escher/message_table_cell_with_editable_text.h b/escher/include/escher/message_table_cell_with_editable_text.h index e5c138b98..089d165fc 100644 --- a/escher/include/escher/message_table_cell_with_editable_text.h +++ b/escher/include/escher/message_table_cell_with_editable_text.h @@ -30,7 +30,7 @@ public: private: void layoutSubviews() override; TextField m_textField; - char m_textBody[Poincare::PrintFloat::k_maxFloatBufferSize]; + char m_textBody[Poincare::PrintFloat::k_maxFloatCharSize]; }; #endif diff --git a/escher/src/editable_text_cell.cpp b/escher/src/editable_text_cell.cpp index 183274454..98f47e1ad 100644 --- a/escher/src/editable_text_cell.cpp +++ b/escher/src/editable_text_cell.cpp @@ -8,7 +8,7 @@ EditableTextCell::EditableTextCell(Responder * parentResponder, InputEventHandle const KDFont * font, float horizontalAlignment, float verticalAlignment, KDColor textColor, KDColor backgroundColor, KDCoordinate topMargin, KDCoordinate rightMargin, KDCoordinate bottomMargin, KDCoordinate leftMargin) : HighlightCell(), Responder(parentResponder), - m_textField(this, m_textBody, Poincare::PrintFloat::k_maxFloatBufferSize, TextField::maxBufferSize(), inputEventHandlerDelegate, delegate, font, horizontalAlignment, verticalAlignment, textColor, backgroundColor), + m_textField(this, m_textBody, Poincare::PrintFloat::k_maxFloatCharSize, TextField::maxBufferSize(), inputEventHandlerDelegate, delegate, font, horizontalAlignment, verticalAlignment, textColor, backgroundColor), m_topMargin(topMargin), m_rightMargin(rightMargin), m_bottomMargin(bottomMargin), diff --git a/escher/src/message_table_cell_with_editable_text.cpp b/escher/src/message_table_cell_with_editable_text.cpp index 909534d89..64b1d1629 100644 --- a/escher/src/message_table_cell_with_editable_text.cpp +++ b/escher/src/message_table_cell_with_editable_text.cpp @@ -5,7 +5,7 @@ MessageTableCellWithEditableText::MessageTableCellWithEditableText(Responder * parentResponder, InputEventHandlerDelegate * inputEventHandlerDelegate, TextFieldDelegate * textFieldDelegate, I18n::Message message) : Responder(parentResponder), MessageTableCell(message), - m_textField(this, m_textBody, Poincare::PrintFloat::k_maxFloatBufferSize, TextField::maxBufferSize(), inputEventHandlerDelegate, textFieldDelegate, KDFont::LargeFont, 1.0f, 0.5f) + m_textField(this, m_textBody, Poincare::PrintFloat::k_maxFloatCharSize, TextField::maxBufferSize(), inputEventHandlerDelegate, textFieldDelegate, KDFont::LargeFont, 1.0f, 0.5f) { m_textBody[0] = '\0'; } diff --git a/ion/src/device/bench/command/adc.cpp b/ion/src/device/bench/command/adc.cpp index 0e697babc..9e3a568fe 100644 --- a/ion/src/device/bench/command/adc.cpp +++ b/ion/src/device/bench/command/adc.cpp @@ -16,8 +16,9 @@ void ADC(const char * input) { float result = Ion::Battery::voltage(); constexpr int precision = 8; constexpr int bufferSize = Poincare::PrintFloat::bufferSizeForFloatsWithPrecision(precision); + constexpr int glyphLength = Poincare::PrintFloat::glyphLengthForFloatWithPrecision(precision); char responseBuffer[bufferSize+4] = {'A', 'D', 'C', '='}; // ADC= - Poincare::PrintFloat::ConvertFloatToText(result, responseBuffer+4, bufferSize, precision, Poincare::Preferences::PrintFloatMode::Decimal); + Poincare::PrintFloat::ConvertFloatToText(result, responseBuffer+4, bufferSize, glyphLength, precision, Poincare::Preferences::PrintFloatMode::Decimal); reply(responseBuffer); } diff --git a/poincare/include/poincare/print_float.h b/poincare/include/poincare/print_float.h index 37c71440d..a3d2474be 100644 --- a/poincare/include/poincare/print_float.h +++ b/poincare/include/poincare/print_float.h @@ -13,11 +13,22 @@ public: constexpr static int k_numberOfStoredSignificantDigits = 14; // ᴇ and ℯ are 3 bytes long constexpr static int k_specialECodePointByteLength = 3; - /* We here define the buffer size to write the longest float possible. + /* We here define the glyph length and the buffer size to write the longest + * float possible. * At maximum, the number has 15 significant digits so, in the worst case it - * has the form -1.99999999999999ᴇ-308 (2+15+3+1+3 char) (the auto mode is + * has the form -1.99999999999999ᴇ-308 (2+15+3+1+3 char) (the decimal mode is * always shorter. */ - constexpr static int k_maxFloatBufferSize = 2+k_numberOfStoredSignificantDigits+k_specialECodePointByteLength+1+3+1; + constexpr static int k_maxFloatGlyphLength = 2 // '-' and '.' + + k_numberOfStoredSignificantDigits // mantissa + + 1 // ᴇ + + 1 // exponant '-' + + 3; // exponant + constexpr static int k_maxFloatCharSize = 2 // '-' and '.' + + k_numberOfStoredSignificantDigits // mantissa + + k_specialECodePointByteLength // ᴇ + + 1 // exponant '-' + + 3 // exponant + + 1; // null-terminated constexpr static int glyphLengthForFloatWithPrecision(int numberOfSignificantDigits) { // The worst case is -1.234ᴇ-328 @@ -27,23 +38,28 @@ public: + 1 // '-' + 3; // exponant } - constexpr static int bufferSizeForFloatsWithPrecision(int numberOfSignificantDigits) { + constexpr static int charSizeForFloatsWithPrecision(int numberOfSignificantDigits) { // The worst case is -1.234ᴇ-328 return 2 // '-' and '.' + numberOfSignificantDigits // mantissa + k_specialECodePointByteLength // ᴇ - + 1 // '-' + + 1 // exponant '-' + 3 // exponant - + 1; // null-terminated buffer + + 1; // null-terminated } + struct TextLengths + { + int CharLength; + int GlyphLength; + }; /* If the buffer size is too small to display the right number of significant * digits, the function forces the scientific mode. If the buffer is still too * small, the text representing the float is empty. * ConvertFloatToText returns the number of characters that have been written * in buffer (excluding the last \0 character). */ template - static int ConvertFloatToText(T d, char * buffer, int bufferSize, int numberOfSignificantDigits, Preferences::PrintFloatMode mode); + static TextLengths ConvertFloatToText(T d, char * buffer, int bufferSize, int availableGlyphLength, int numberOfSignificantDigits, Preferences::PrintFloatMode mode); // Engineering notation static int EngineeringExponentFromBase10Exponent(int exponent); @@ -59,7 +75,7 @@ public: private: template - static int ConvertFloatToTextPrivate(T f, char * buffer, int bufferSize, int numberOfSignificantDigits, Preferences::PrintFloatMode mode, int * numberOfRemovedZeros); + static TextLengths ConvertFloatToTextPrivate(T f, char * buffer, int bufferSize, int availableGlyphLength, int numberOfSignificantDigits, Preferences::PrintFloatMode mode); class Long final { public: diff --git a/poincare/src/float.cpp b/poincare/src/float.cpp index 74dfd10d7..3052747ed 100644 --- a/poincare/src/float.cpp +++ b/poincare/src/float.cpp @@ -31,13 +31,13 @@ int FloatNode::simplificationOrderSameType(const ExpressionNode * e, bool asc template int FloatNode::serialize(char * buffer, int bufferSize, Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const { - return PrintFloat::ConvertFloatToText(m_value, buffer, bufferSize, numberOfSignificantDigits, floatDisplayMode); + return PrintFloat::ConvertFloatToText(m_value, buffer, bufferSize, PrintFloat::k_maxFloatGlyphLength, numberOfSignificantDigits, floatDisplayMode).CharLength; } template Layout FloatNode::createLayout(Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const { - char buffer[PrintFloat::k_maxFloatBufferSize]; - int numberOfChars = serialize(buffer, PrintFloat::k_maxFloatBufferSize, floatDisplayMode, numberOfSignificantDigits); + char buffer[PrintFloat::k_maxFloatCharSize]; + int numberOfChars = serialize(buffer, PrintFloat::k_maxFloatCharSize, floatDisplayMode, numberOfSignificantDigits); return LayoutHelper::String(buffer, numberOfChars); } diff --git a/poincare/src/infinity.cpp b/poincare/src/infinity.cpp index b00b03d19..8a537a68e 100644 --- a/poincare/src/infinity.cpp +++ b/poincare/src/infinity.cpp @@ -24,7 +24,7 @@ int InfinityNode::serialize(char * buffer, int bufferSize, Preferences::PrintFlo if (bufferSize == 0) { return -1; } - return PrintFloat::ConvertFloatToText(m_negative ? -INFINITY : INFINITY, buffer, bufferSize, numberOfSignificantDigits, floatDisplayMode); + return PrintFloat::ConvertFloatToText(m_negative ? -INFINITY : INFINITY, buffer, bufferSize, PrintFloat::k_maxFloatGlyphLength, numberOfSignificantDigits, floatDisplayMode).CharLength; } template Evaluation InfinityNode::templatedApproximate() const { diff --git a/poincare/src/integer.cpp b/poincare/src/integer.cpp index f59f72044..9e258d8a7 100644 --- a/poincare/src/integer.cpp +++ b/poincare/src/integer.cpp @@ -166,7 +166,7 @@ int Integer::serialize(char * buffer, int bufferSize) const { return 0; } if (isOverflow()) { - return PrintFloat::ConvertFloatToText(m_negative ? -INFINITY : INFINITY, buffer, bufferSize, PrintFloat::k_numberOfStoredSignificantDigits, Preferences::PrintFloatMode::Decimal); + return PrintFloat::ConvertFloatToText(m_negative ? -INFINITY : INFINITY, buffer, bufferSize, PrintFloat::k_maxFloatGlyphLength, PrintFloat::k_numberOfStoredSignificantDigits, Preferences::PrintFloatMode::Decimal).CharLength; } Integer base(10); @@ -185,7 +185,7 @@ int Integer::serialize(char * buffer, int bufferSize) const { d.quotient.isZero())) { char c = char_from_digit(d.remainder.isZero() ? 0 : d.remainder.digit(0)); if (length >= bufferSize-1) { - return PrintFloat::ConvertFloatToText(NAN, buffer, bufferSize, PrintFloat::k_numberOfStoredSignificantDigits, Preferences::PrintFloatMode::Decimal); + return PrintFloat::ConvertFloatToText(NAN, buffer, bufferSize, PrintFloat::k_maxFloatGlyphLength, PrintFloat::k_numberOfStoredSignificantDigits, Preferences::PrintFloatMode::Decimal).CharLength; } length += SerializationHelper::CodePoint(buffer + length, bufferSize - length, c); d = udiv(d.quotient, base); diff --git a/poincare/src/print_float.cpp b/poincare/src/print_float.cpp index c0bbcb802..f18a38412 100644 --- a/poincare/src/print_float.cpp +++ b/poincare/src/print_float.cpp @@ -100,7 +100,7 @@ void PrintFloat::PrintLongWithDecimalMarker(char * buffer, int bufferLength, Lon * in first position. When called by ConvertFloatToText, the buffer length is * always > 0 as we asserted a minimal number of available chars. */ assert(bufferLength > 0 && decimalMarkerPosition != 0); - constexpr int tempBufferSize = PrintFloat::k_maxFloatBufferSize; + constexpr int tempBufferSize = PrintFloat::k_maxFloatCharSize; char tempBuffer[tempBufferSize]; int intLength = i.serialize(tempBuffer, tempBufferSize); int firstDigitChar = UTF8Helper::CodePointIs(tempBuffer, '-') ? 1 : 0; @@ -128,30 +128,30 @@ void PrintFloat::PrintLongWithDecimalMarker(char * buffer, int bufferLength, Lon } template -int PrintFloat::ConvertFloatToText(T f, char * buffer, int bufferSize, +PrintFloat::TextLengths PrintFloat::ConvertFloatToText(T f, char * buffer, int bufferSize, int glyphLength, int numberOfSignificantDigits, Preferences::PrintFloatMode mode) { assert(numberOfSignificantDigits > 0); assert(bufferSize > 0); - /* Truncate the buffer if needed. + /* Assert that the glyphLength is capped. * Example: 1+1.234E-30+... in decimal mode, because we do not want the fill * the buffer with the decimal version of 1.234E-30. */ - int truncatedBufferSize = minInt(PrintFloat::k_maxFloatBufferSize, bufferSize); + assert(glyphLength < k_maxFloatGlyphLength); - int numberOfZerosRemoved = 0; - int requiredLength = ConvertFloatToTextPrivate(f, buffer, truncatedBufferSize, numberOfSignificantDigits, mode, &numberOfZerosRemoved); + TextLengths requiredLengths = ConvertFloatToTextPrivate(f, buffer, bufferSize, glyphLength, numberOfSignificantDigits, mode); /* If the required buffer size overflows the buffer size, we force the display * mode to scientific. */ - if (mode == Preferences::PrintFloatMode::Decimal && requiredLength >= truncatedBufferSize) { - requiredLength = ConvertFloatToTextPrivate(f, buffer, truncatedBufferSize, numberOfSignificantDigits, Preferences::PrintFloatMode::Scientific, &numberOfZerosRemoved); + if (mode == Preferences::PrintFloatMode::Decimal && (requiredLengths.CharLength > bufferSize - 1 || requiredLengths.GlyphLength > glyphLength)) { + requiredLengths = ConvertFloatToTextPrivate(f, buffer, bufferSize, glyphLength, numberOfSignificantDigits, Preferences::PrintFloatMode::Scientific); } - if (requiredLength >= truncatedBufferSize) { + if (requiredLengths.CharLength > bufferSize - 1 || requiredLengths.GlyphLength > glyphLength) { buffer[0] = 0; - return 0; + /* We still return the required sizes even if we could not write the float + * in the buffer in order to indicate that we overflew the buffer. */ } - return requiredLength; + return requiredLengths; } int PrintFloat::EngineeringExponentFromBase10Exponent(int exponent) { @@ -163,37 +163,43 @@ int PrintFloat::EngineeringExponentFromBase10Exponent(int exponent) { } template -int PrintFloat::ConvertFloatToTextPrivate(T f, char * buffer, int bufferSize, int numberOfSignificantDigits, Preferences::PrintFloatMode mode, int * numberOfRemovedZeros) { +PrintFloat::TextLengths PrintFloat::ConvertFloatToTextPrivate(T f, char * buffer, int bufferSize, int glyphLength, int numberOfSignificantDigits, Preferences::PrintFloatMode mode) { assert(numberOfSignificantDigits > 0); assert(bufferSize > 0); + assert(glyphLength > 0 && glyphLength < k_maxFloatGlyphLength); + int availableCharLength = minInt(bufferSize-1, glyphLength); + TextLengths exceptionResult = {.CharLength = bufferSize, .GlyphLength = glyphLength+1}; //TODO: accelerate for f between 0 and 10 ? if (std::isinf(f)) { // Infinity bool writeMinusSign = f < 0; assert(UTF8Decoder::CharSizeOfCodePoint('-') == 1); - int requiredLength = (writeMinusSign ? 1 : 0) + Infinity::NameSize() - 1; - if (requiredLength > bufferSize - 1) { + int requiredCharLength = (writeMinusSign ? 1 : 0) + Infinity::NameSize() - 1; + TextLengths requiredTextLengths = {.CharLength = requiredCharLength, .GlyphLength = requiredCharLength}; + if (requiredCharLength > availableCharLength) { // We will not be able to print - return requiredLength; + return requiredTextLengths; } // Write inf or -inf int currentChar = 0; if (f < 0) { - currentChar+= SerializationHelper::CodePoint(buffer, bufferSize, '-'); + currentChar += SerializationHelper::CodePoint(buffer, bufferSize, '-'); } assert(bufferSize - currentChar > 0); strlcpy(buffer+currentChar, Infinity::Name(), bufferSize-currentChar); - return requiredLength; + return requiredTextLengths; } if (std::isnan(f)) { // Nan - constexpr int requiredLength = Undefined::NameSize() - 1; - if (requiredLength - 1 > bufferSize - 1) { + constexpr int requiredCharLength = Undefined::NameSize() - 1; + constexpr TextLengths requiredTextLengths = {.CharLength = requiredCharLength, .GlyphLength = requiredCharLength}; + if (requiredCharLength > availableCharLength) { // We will not be able to print - return requiredLength; + return requiredTextLengths; } - return strlcpy(buffer, Undefined::Name(), bufferSize); + strlcpy(buffer, Undefined::Name(), bufferSize); + return requiredTextLengths; } int exponentInBase10 = IEEE754::exponentBase10(f); @@ -227,7 +233,7 @@ int PrintFloat::ConvertFloatToTextPrivate(T f, char * buffer, int bufferSize, in * displaying 12345 with 2 significant digis in Decimal mode for instance. * This exception is caught by ConvertFloatToText and forces the mode to * Scientific */ - return bufferSize + 1; + return exceptionResult; } // Correct the number of digits in mantissa after rounding @@ -275,9 +281,6 @@ int PrintFloat::ConvertFloatToTextPrivate(T f, char * buffer, int bufferSize, in assert(mantissa < 1000); Long::MultiplySmallLongByTen(dividend); } - if (numberOfRemovedZeros != nullptr) { - *numberOfRemovedZeros = -numberOfZeroesToAdd; - } } } if (removeZeroes) { @@ -298,12 +301,9 @@ int PrintFloat::ConvertFloatToTextPrivate(T f, char * buffer, int bufferSize, in Long::DivisionByTen(dividend, "ient, &digit); numberOfZerosRemoved++; } - if (numberOfCharsForMantissaWithoutSign > bufferSize - 1) { + if (numberOfCharsForMantissaWithoutSign > availableCharLength) { // Escape now if the true number of needed digits is not required - return bufferSize + 1; - } - if (numberOfRemovedZeros != nullptr) { - *numberOfRemovedZeros = numberOfZerosRemoved; + return exceptionResult; } } @@ -317,9 +317,9 @@ int PrintFloat::ConvertFloatToTextPrivate(T f, char * buffer, int bufferSize, in assert(UTF8Decoder::CharSizeOfCodePoint('.') == 1); numberOfCharsForMantissaWithoutSign++; } - if (numberOfCharsForMantissaWithoutSign > bufferSize - 1) { + if (numberOfCharsForMantissaWithoutSign > availableCharLength) { // Escape now if the true number of needed digits is not required - return bufferSize + 1; + return exceptionResult; } /* Find the position of the decimal marker position */ @@ -340,9 +340,9 @@ int PrintFloat::ConvertFloatToTextPrivate(T f, char * buffer, int bufferSize, in /* Part III: Sign */ int numberOfCharsForMantissaWithSign = numberOfCharsForMantissaWithoutSign + (f >= 0 ? 0 : 1); - if (numberOfCharsForMantissaWithSign > bufferSize - 1) { + if (numberOfCharsForMantissaWithSign > availableCharLength) { // Exception 2: we will overflow the buffer - return bufferSize + 1; + return exceptionResult; } /* Part IV: Exponent */ @@ -360,15 +360,20 @@ int PrintFloat::ConvertFloatToTextPrivate(T f, char * buffer, int bufferSize, in assert(UTF8Decoder::CharSizeOfCodePoint('-') == 1); // Print mantissa bool doNotWriteExponent = (mode == Preferences::PrintFloatMode::Decimal) || (exponent == 0); - int neededNumberOfChars = numberOfCharsForMantissaWithSign + (doNotWriteExponent ? 0 : UTF8Decoder::CharSizeOfCodePoint(UCodePointLatinLetterSmallCapitalE) + numberOfCharExponent); - if (neededNumberOfChars > bufferSize - 1) { + int neededNumberOfChars = numberOfCharsForMantissaWithSign; + int neededNumberOfGlyphs = numberOfCharsForMantissaWithSign; + if (!doNotWriteExponent) { + neededNumberOfChars += UTF8Decoder::CharSizeOfCodePoint(UCodePointLatinLetterSmallCapitalE) + numberOfCharExponent; + neededNumberOfGlyphs += 1 + numberOfCharExponent; + } + if (neededNumberOfChars > bufferSize - 1 || neededNumberOfGlyphs > glyphLength) { // Exception 3: We are about to overflow the buffer. - return neededNumberOfChars; + return exceptionResult; } PrintLongWithDecimalMarker(buffer, numberOfCharsForMantissaWithSign, dividend, decimalMarkerPosition); if (doNotWriteExponent) { buffer[numberOfCharsForMantissaWithSign] = 0; - return numberOfCharsForMantissaWithSign; + return {.CharLength = numberOfCharsForMantissaWithSign, .GlyphLength = numberOfCharsForMantissaWithSign}; } // Print exponent assert(numberOfCharsForMantissaWithSign < bufferSize); @@ -378,10 +383,10 @@ int PrintFloat::ConvertFloatToTextPrivate(T f, char * buffer, int bufferSize, in PrintLongWithDecimalMarker(buffer + currentNumberOfChar, numberOfCharExponent, dividend, -1); buffer[currentNumberOfChar + numberOfCharExponent] = 0; assert(neededNumberOfChars == currentNumberOfChar + numberOfCharExponent); - return currentNumberOfChar + numberOfCharExponent; + return {.CharLength = currentNumberOfChar + numberOfCharExponent, .GlyphLength = numberOfCharsForMantissaWithSign + 1 + numberOfCharExponent}; } -template int PrintFloat::ConvertFloatToText(float, char*, int, int, Preferences::Preferences::PrintFloatMode); -template int PrintFloat::ConvertFloatToText(double, char*, int, int, Preferences::Preferences::PrintFloatMode); +template PrintFloat::TextLengths PrintFloat::ConvertFloatToText(float, char*, int, int, int, Preferences::Preferences::PrintFloatMode); +template PrintFloat::TextLengths PrintFloat::ConvertFloatToText(double, char*, int, int, int, Preferences::Preferences::PrintFloatMode); } diff --git a/poincare/test/print_float.cpp b/poincare/test/print_float.cpp index 3c53cbf88..8dbe1a247 100644 --- a/poincare/test/print_float.cpp +++ b/poincare/test/print_float.cpp @@ -21,7 +21,7 @@ void assert_float_prints_to(T a, const char * result, Preferences::PrintFloatMod memset(taggedBuffer, tag, taggedAreaSize); char * buffer = taggedBuffer + tagSize; - PrintFloat::ConvertFloatToText(a, buffer, bufferSize, significantDigits, mode); + PrintFloat::ConvertFloatToText(a, buffer, bufferSize, glyphLengthForFloatWithPrecision(significantDigits), significantDigits, mode); for (int i = 0; i < tagSize; i++) { quiz_assert_print_if_failure(taggedBuffer[i] == tag, result);