GithubHelp home page GithubHelp logo

write(WriterI*, double) trims exponent about bx HOT 2 CLOSED

jdryg avatar jdryg commented on July 17, 2024
write(WriterI*, double) trims exponent

from bx.

Comments (2)

jdryg avatar jdryg commented on July 17, 2024

I don't know if this is your final fix but unfortunately, it does not work when a precision is specified in the above case.
Also, it does not work the same as before for all numbers when no precision is specified (default precision = 6 digits).

I didn't realize there were tests in bx so I tried adding more of them in the "vsnprintf f" test case.

#if 0 // Original code
REQUIRE(test("0.00390625", "%f", 0.00390625));
#else
REQUIRE(test("0.003906",   "%f",   0.00390625) ); // No precision is specified so 6 digits are expected after the dot.
#endif
REQUIRE(test("-1.234567e-9", "%f", -1.234567e-9) );

// Test exponent with precision specifier.
REQUIRE(test("-1e-9", "%.0f", -1.234567e-9) );
REQUIRE(test("-1.2e-9", "%.1f", -1.234567e-9) );
REQUIRE(test("-1.23e-9", "%.2f", -1.234567e-9) );
REQUIRE(test("-1.234e-9", "%.3f", -1.234567e-9) );
REQUIRE(test("-1.2345e-9", "%.4f", -1.234567e-9) );
REQUIRE(test("-1.23456e-9", "%.5f", -1.234567e-9) );
REQUIRE(test("-1.234567e-9", "%.6f", -1.234567e-9) );
REQUIRE(test("-1.2345670e-9", "%.7f", -1.234567e-9) ); // Extra 0s with exponent
REQUIRE(test("-1.23456700e-9", "%.8f", -1.234567e-9) );
REQUIRE(test("-1.234567000e-9", "%.9f", -1.234567e-9) );
REQUIRE(test("-1.2345670000e-9", "%.10f", -1.234567e-9) );

// Test transcendental number
REQUIRE(test("3.141592", "%f", 3.1415926535897932) );
REQUIRE(test("3", "%.0f", 3.1415926535897932) );
REQUIRE(test("3.1", "%.1f", 3.1415926535897932) );
REQUIRE(test("3.14", "%.2f", 3.1415926535897932) );
REQUIRE(test("3.141", "%.3f", 3.1415926535897932) );
REQUIRE(test("3.1415", "%.4f", 3.1415926535897932) );
REQUIRE(test("3.14159", "%.5f", 3.1415926535897932) );
REQUIRE(test("3.141592", "%.6f", 3.1415926535897932) );
REQUIRE(test("3.1415926", "%.7f", 3.1415926535897932) );
REQUIRE(test("3.14159265", "%.8f", 3.1415926535897932) );
REQUIRE(test("3.141592653", "%.9f", 3.1415926535897932) );
REQUIRE(test("3.1415926535", "%.10f", 3.1415926535897932) );
REQUIRE(test("3.14159265358", "%.11f", 3.1415926535897932) );
REQUIRE(test("3.141592653589", "%.12f", 3.1415926535897932) );
REQUIRE(test("3.1415926535897", "%.13f", 3.1415926535897932) );
REQUIRE(test("3.14159265358979", "%.14f", 3.1415926535897932) );
REQUIRE(test("3.141592653589793", "%.15f", 3.1415926535897932) );
REQUIRE(test("3.1415926535897930", "%.16f", 3.1415926535897932) ); // The last digit is replaced by 0 because toString() has a 15-digit precision (?)

// Both of the above tests combined (transcendental number with large negative exponent)
REQUIRE(test("-3.141592e-9", "%f", -3.1415926535897932e-9) );
REQUIRE(test("-3e-9", "%.0f", -3.1415926535897932e-9) );
REQUIRE(test("-3.1e-9", "%.1f", -3.1415926535897932e-9) );
REQUIRE(test("-3.14e-9", "%.2f", -3.1415926535897932e-9) );
REQUIRE(test("-3.141e-9", "%.3f", -3.1415926535897932e-9) );
REQUIRE(test("-3.1415e-9", "%.4f", -3.1415926535897932e-9) );
REQUIRE(test("-3.14159e-9", "%.5f", -3.1415926535897932e-9) );
REQUIRE(test("-3.141592e-9", "%.6f", -3.1415926535897932e-9) );
REQUIRE(test("-3.1415926e-9", "%.7f", -3.1415926535897932e-9) );
REQUIRE(test("-3.14159265e-9", "%.8f", -3.1415926535897932e-9) );
REQUIRE(test("-3.141592653e-9", "%.9f", -3.1415926535897932e-9) );
REQUIRE(test("-3.1415926535e-9", "%.10f", -3.1415926535897932e-9) );
REQUIRE(test("-3.14159265358e-9", "%.11f", -3.1415926535897932e-9) );
REQUIRE(test("-3.141592653589e-9", "%.12f", -3.1415926535897932e-9) );
REQUIRE(test("-3.1415926535897e-9", "%.13f", -3.1415926535897932e-9) );
REQUIRE(test("-3.14159265358979e-9", "%.14f", -3.1415926535897932e-9) );
REQUIRE(test("-3.141592653589793e-9", "%.15f", -3.1415926535897932e-9) );
REQUIRE(test("-3.1415926535897930e-9", "%.16f", -3.1415926535897932e-9) ); // The last digit is replaced by 0 because toString() has a 15-digit precision (?)

And below is my version (including your code in #if 0/#endif block):

static int32_t write(WriterI* _writer, double _d, const Param& _param, Error* _err)
{
	char str[1024];
	int32_t len = toString(str, sizeof(str), _d);

	if (len == 0)
	{
		return 0;
	}

	if (_param.upper)
	{
		toUpperUnsafe(str, len);
	}

	const char* dot = strFind(str, INT32_MAX, '.');
	if (NULL != dot)
	{
#if 0 // Original code
		const int32_t prec = INT32_MAX == _param.prec ? len - (dot + 1 - str) : _param.prec;
		const int32_t precLen = int32_t(
				dot
				+ min(prec + _param.spec, 1)
				+ prec
				- str
				);
		if (precLen > len)
		{
			for (int32_t ii = len; ii < precLen; ++ii)
			{
				str[ii] = '0';
			}

			str[precLen] = '\0';
		}

		len = precLen;
#else
		const int32_t prec = INT32_MAX == _param.prec ? 6 : _param.prec;
		const char* strEnd = str + len;
		const char* exponent = strFind(str, INT32_MAX, 'e');
		const char* fracEnd = NULL != exponent ? exponent : strEnd;
		char* fracBegin = &str[dot - str + min(prec + _param.spec, 1)];
		const int32_t curPrec = int32_t(fracEnd - fracBegin);

		// Move exponent to its final location after trimming or adding extra 0s.
		if (fracEnd != strEnd)
		{
			const int32_t exponentLen = int32_t(strEnd - fracEnd);
			char* finalExponentPtr = &fracBegin[prec];
			memMove(finalExponentPtr, fracEnd, exponentLen); // NOTE: Use memMove because there may be overlap.
			finalExponentPtr[exponentLen] = '\0';
			len = int32_t(&finalExponentPtr[exponentLen] - str);
		}
		else
		{
			len = (int32_t)(fracBegin + prec - str);
		}

		if (curPrec < prec)
		{
			for (int32_t ii = curPrec; ii < prec; ++ii)
			{
				fracBegin[ii] = '0';
			}
		}
#endif
	} else {
		// TODO: If '#' is present (_param.spec == true) add dot?
	}

	return write(_writer, str, len, _param, _err);
}

It works for all the above cases. As a bonus, it also works for all tests in vsnprintf modifiers case (the test failed with your fix).

I don't want to mess with the library's code style so please cleanup the code as you see fit.

EDIT: Changed "width" to "precision" in all cases. This issue is about the precision specifier :)

from bx.

bkaradzic avatar bkaradzic commented on July 17, 2024

Send PR. :)

from bx.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.