mirror of
https://github.com/UpsilonNumworks/Upsilon.git
synced 2026-03-19 05:40:38 +01:00
[poincare] In float, add method to convert float to text
Change-Id: I9a85c02e0b2843ee999847b821b9d24f1452eb5d
This commit is contained in:
@@ -34,15 +34,16 @@ objs += $(addprefix poincare/src/layout/,\
|
||||
|
||||
tests += $(addprefix poincare/test/,\
|
||||
addition.cpp\
|
||||
float.cpp\
|
||||
fraction.cpp\
|
||||
integer.cpp\
|
||||
identity.cpp\
|
||||
integer.cpp\
|
||||
product.cpp\
|
||||
simplify_utils.cpp\
|
||||
simplify_addition.cpp\
|
||||
simplify_product.cpp\
|
||||
trigo.cpp\
|
||||
subtraction.cpp\
|
||||
trigo.cpp\
|
||||
)
|
||||
|
||||
ifdef POINCARE_TESTS_PRINT_EXPRESSIONS
|
||||
|
||||
@@ -4,17 +4,36 @@
|
||||
#include <poincare/leaf_expression.h>
|
||||
|
||||
class Float : public LeafExpression {
|
||||
public:
|
||||
Float(float f);
|
||||
~Float();
|
||||
public:
|
||||
Float(float f);
|
||||
~Float();
|
||||
|
||||
ExpressionLayout * createLayout() const override;
|
||||
float approximate(Context& context) const override;
|
||||
Type type() const override;
|
||||
Expression * clone() const override;
|
||||
bool valueEquals(const Expression * e) const override;
|
||||
private:
|
||||
float m_float;
|
||||
ExpressionLayout * createLayout() const override;
|
||||
float approximate(Context& context) const override;
|
||||
Type type() const override;
|
||||
Expression * clone() const override;
|
||||
bool valueEquals(const Expression * e) const override;
|
||||
|
||||
enum class DisplayMode {
|
||||
Scientific,
|
||||
Decimal
|
||||
};
|
||||
|
||||
/* The parameter 'DisplayMode' refers to the way to display float 'scientific' or
|
||||
* 'decimal'. The code only handles 'scientific' so far. */
|
||||
void convertFloatToText(char * buffer, int bufferSize, int numberOfDigitsInMantissa, DisplayMode mode = DisplayMode::Scientific);
|
||||
|
||||
private:
|
||||
/* This function prints the int i in the buffer with a '.' at the position
|
||||
* specified by the decimalMarkerPosition. It starts printing at the end of the
|
||||
* buffer and print from right to left. The integer given should be of the right
|
||||
* length to be written in bufferLength chars. If the integer is to small, the
|
||||
* empty chars on the left side are completed with '0'. If the integer is too
|
||||
* big, the printing stops when no more empty chars are available without
|
||||
* returning any warning. */
|
||||
void static printBase10IntegerWithDecimalMarker(char * buffer, int bufferSize, int i, int decimalMarkerPosition);
|
||||
|
||||
float m_float;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -2,6 +2,7 @@ extern "C" {
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
}
|
||||
|
||||
#include <poincare/float.h>
|
||||
@@ -33,3 +34,94 @@ bool Float::valueEquals(const Expression * e) const {
|
||||
assert(e->type() == Expression::Type::Float);
|
||||
return m_float == ((Float *)e)->m_float;
|
||||
}
|
||||
|
||||
void Float::printBase10IntegerWithDecimalMarker(char * buffer, int bufferSize, int i, int decimalMarkerPosition) {
|
||||
/* The decimal marker position is always preceded by a char, thus, it is never
|
||||
* in first position. When called by convertFloatToText, the buffer length is
|
||||
* always > 0 as we asserted a minimal number of available chars. */
|
||||
assert(bufferSize > 0 && decimalMarkerPosition != 0);
|
||||
int endChar = bufferSize - 1, startChar = 0;
|
||||
int dividend = i, digit = 0, quotien = 0;
|
||||
if (i < 0) {
|
||||
buffer[startChar++] = '-';
|
||||
dividend = -i;
|
||||
decimalMarkerPosition += 1;
|
||||
}
|
||||
/* This loop acts correctly as we asserted the endChar >= 0 and
|
||||
* decimalMarkerPosition != 0 */
|
||||
do {
|
||||
if (endChar == decimalMarkerPosition) {
|
||||
buffer[endChar--] = '.';
|
||||
}
|
||||
quotien = dividend/10;
|
||||
digit = dividend - quotien*10;
|
||||
buffer[endChar--] = '0'+digit;
|
||||
dividend = quotien;
|
||||
} while (endChar >= startChar);
|
||||
}
|
||||
|
||||
void Float::convertFloatToText(char * buffer, int bufferSize,
|
||||
int numberOfDigitsInMantissa, DisplayMode mode) {
|
||||
/* We here assert that the buffer is long enough to display with the right
|
||||
* number of digits in the mantissa. If numberOfDigitsInMantissa = 7, the
|
||||
* worst case has the form -1.999999e-38 (7+6+1 char). */
|
||||
assert(bufferSize > 6 + numberOfDigitsInMantissa);
|
||||
|
||||
// TO DO: if (isinf(m_float)) {
|
||||
float maximalFloat = 3.4f*powf(10, 38);
|
||||
if (m_float > maximalFloat || m_float < -maximalFloat) {
|
||||
buffer[0] = 'N';
|
||||
buffer[1] = 'a';
|
||||
buffer[2] = 'N';
|
||||
buffer[3] = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
float logBase10 = m_float != 0.0f ? log10f(fabsf(m_float)) : 0;
|
||||
int exponentInBase10 = logBase10;
|
||||
if ((int)m_float == 0 and logBase10 != exponentInBase10) {
|
||||
/* For floats < 0, the exponent in base 10 is the inferior integer part of
|
||||
* log10(float). We thus decrement the exponent for float < 0 whose exponent
|
||||
* is not an integer. */
|
||||
exponentInBase10--;
|
||||
}
|
||||
|
||||
int numberOfCharExponent = exponentInBase10 != 0 ? log10f(fabsf((float)exponentInBase10)) + 1 : 1;
|
||||
if (exponentInBase10 < 0){
|
||||
// If the exponent is < 0, we need a additional char for the sign
|
||||
numberOfCharExponent++;
|
||||
}
|
||||
|
||||
/* Future optimisation, if mode > 0, find the position of decimalMarker and
|
||||
* decide whether to display the exponent. */
|
||||
|
||||
// Number of char available for the mantissa
|
||||
int availableCharsForMantissaWithoutSign = numberOfDigitsInMantissa + 1;
|
||||
int availableCharsForMantissaWithSign = m_float >= 0 ? availableCharsForMantissaWithoutSign : availableCharsForMantissaWithoutSign + 1;
|
||||
|
||||
// Compute mantissa
|
||||
/* The number of digits in an integer is capped because the maximal integer is
|
||||
* 2^31 - 1. As our mantissa is an integer, we assert that we stay beyond this
|
||||
* threshold during computation. */
|
||||
int numberMaximalOfCharsInInteger = log10f(powf(2, 31));
|
||||
assert(availableCharsForMantissaWithoutSign - 1 < numberMaximalOfCharsInInteger);
|
||||
int mantissa = m_float * powf(10, availableCharsForMantissaWithoutSign - exponentInBase10 - 2);
|
||||
|
||||
// Supress the 0 on the right side of the mantissa
|
||||
int dividend = fabsf((float)mantissa);
|
||||
int quotien = dividend/10;
|
||||
int digit = dividend - quotien*10;
|
||||
while (digit == 0 && availableCharsForMantissaWithSign > 2) {
|
||||
mantissa = mantissa/10;
|
||||
availableCharsForMantissaWithSign--;
|
||||
dividend = quotien;
|
||||
quotien = dividend/10;
|
||||
digit = dividend - quotien*10;
|
||||
}
|
||||
|
||||
// Print sequentially mantissa and exponent
|
||||
printBase10IntegerWithDecimalMarker(buffer, availableCharsForMantissaWithSign, mantissa, 1);
|
||||
buffer[availableCharsForMantissaWithSign] = 'e';
|
||||
printBase10IntegerWithDecimalMarker(buffer+availableCharsForMantissaWithSign+1, numberOfCharExponent, exponentInBase10, -1);
|
||||
buffer[availableCharsForMantissaWithSign+1+numberOfCharExponent] = 0;
|
||||
}
|
||||
|
||||
26
poincare/test/float.cpp
Normal file
26
poincare/test/float.cpp
Normal file
@@ -0,0 +1,26 @@
|
||||
#include <quiz.h>
|
||||
#include <poincare.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
|
||||
QUIZ_CASE(poincare_float_to_text) {
|
||||
char buffer [14];
|
||||
Float(123.456).convertFloatToText(buffer, 14, 7);
|
||||
assert(strcmp(buffer, "1.23456e2") == 0);
|
||||
Float(1.234567891011).convertFloatToText(buffer, 14, 7);
|
||||
assert(strcmp(buffer, "1.234567e0") == 0);
|
||||
Float(2).convertFloatToText(buffer, 14, 7);
|
||||
assert(strcmp(buffer, "2.e0") == 0);
|
||||
Float(123456789).convertFloatToText(buffer, 14, 7);
|
||||
assert(strcmp(buffer, "1.234567e8") == 0);
|
||||
Float(0.00000123456789).convertFloatToText(buffer, 14, 7);
|
||||
assert(strcmp(buffer, "1.234567e-6") == 0);
|
||||
Float(0.99).convertFloatToText(buffer, 14, 7);
|
||||
assert(strcmp(buffer, "9.9e-1") == 0);
|
||||
Float(-123.456789).convertFloatToText(buffer, 14, 7);
|
||||
assert(strcmp(buffer, "-1.234567e2") == 0);
|
||||
Float(-0.000123456789).convertFloatToText(buffer, 14, 7);
|
||||
assert(strcmp(buffer, "-1.234567e-4") == 0);
|
||||
Float(0).convertFloatToText(buffer, 14, 7);
|
||||
assert(strcmp(buffer, "0.e0") == 0);
|
||||
}
|
||||
Reference in New Issue
Block a user