Fix ecvt/fcvt issues w.r.t. value==0 and ndigit==0 (#1282)

Before this commit, cosmopolitan had some issues with handling arguments
of 0 and signs, such as returning an incorrect sign when the input value
== -0.0, and incorrectly handling ndigit == 0 on fcvt (ndigit determines
the amount of digits *after* the radix character on fcvt, thus the parts
before it still must be outputted before fcvt's job is completely done).

This patch fixes these issues, and adds tests with corresponding inputs.
This commit is contained in:
Gabriel Ravier 2024-09-08 03:08:11 +02:00 committed by GitHub
parent dc579b79cd
commit f882887178
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 45 additions and 4 deletions

View file

@ -22,6 +22,7 @@
Materiel Command, USAF, under agreement number F39502-99-1-0512.
SUCH DAMAGE.
*/
#include "libc/math.h"
#include "libc/mem/mem.h"
#include "libc/runtime/runtime.h"
#include "libc/str/str.h"
@ -53,8 +54,11 @@ __cvt(double value, int ndigit, int *decpt, int *sign, int fmode, int pad)
char *p, *rve, c;
size_t siz;
if (ndigit == 0) {
*sign = value < 0.0;
// Note that we exclude the case of fmode here, since for fcvt having
// `ndigit == 0` just means we have to output 0 digits *after* the radix
// character
if (ndigit == 0 && !fmode) {
*sign = signbit(value);
*decpt = 0;
return ("");
}
@ -71,9 +75,11 @@ __cvt(double value, int ndigit, int *decpt, int *sign, int fmode, int pad)
/* __dtoa() doesn't allocate space for 0 so we do it by hand */
if (value == 0.0) {
*decpt = 1 - fmode; /* 1 for 'e', 0 for 'f' */
*sign = 0;
*sign = signbit(value);
if ((rve = s = malloc(siz)) == NULL)
return(NULL);
// handle fcvt(0, 0, ...) by returning ""
if (siz > 1)
*rve++ = '0';
*rve = '\0';
} else {

View file

@ -31,3 +31,38 @@ TEST(fcvt, test) {
ASSERT_EQ(1, decpt);
ASSERT_EQ(0, sign);
}
TEST(ecvt, minus0) {
int decpt = 110000000, sign = 110000000;
ASSERT_STREQ("00000", ecvt(-0.0, 5, &decpt, &sign));
ASSERT_LE(0, decpt);
ASSERT_GE(1, decpt);
ASSERT_EQ(1, sign);
}
TEST(ecvt, minus0ndigits0) {
int decpt = 110000000, sign = 110000000;
ASSERT_STREQ("", ecvt(-0.0, 0, &decpt, &sign));
ASSERT_LE(0, decpt);
ASSERT_GE(1, decpt);
ASSERT_EQ(1, sign);
}
TEST(fcvt, ndigits0) {
int decpt = 110000000, sign = 110000000;
ASSERT_STREQ("1", fcvt(0.6, 0, &decpt, &sign));
ASSERT_EQ(1, decpt);
ASSERT_EQ(0, sign);
}
TEST(fcvt, minus0ndigits0) {
int decpt = 110000000, sign = 110000000;
ASSERT_STREQ("", fcvt(-0.0, 0, &decpt, &sign));
ASSERT_LE(0, decpt);
ASSERT_GE(1, decpt);
ASSERT_EQ(1, sign);
}