Floats choosable between double and float

This commit is contained in:
No Default Name 2022-04-28 21:18:28 +02:00
parent a1efa1e77f
commit 5cdc8d4c27
3 changed files with 60 additions and 33 deletions

71
cJSON.c
View File

@ -69,7 +69,6 @@
#endif #endif
#define false ((cJSON_bool)0) #define false ((cJSON_bool)0)
/* define our own int max and min */
#ifdef CJSON_INT_USE_LONGLONG #ifdef CJSON_INT_USE_LONGLONG
#define CJSON_INT_MAX LLONG_MAX #define CJSON_INT_MAX LLONG_MAX
#define CJSON_INT_MIN LLONG_MIN #define CJSON_INT_MIN LLONG_MIN
@ -82,7 +81,17 @@
#define intfmt "%d" #define intfmt "%d"
#endif #endif
#ifdef CJSON_FLOAT_USE_FLOAT
#define strtofloat strtof
#define has_no_decimals(d) (d == floorf(d))
#define floatfmt_shorter "%1.6g"
#define floatfmt_longer "%1.9g"
#else
#define strtofloat strtod
#define has_no_decimals(d) (d == floor(d)) #define has_no_decimals(d) (d == floor(d))
#define floatfmt_shorter "%1.15g"
#define floatfmt_longer "%1.17g"
#endif
/* define isnan and isinf for ANSI C, if in C99 or above, isnan and isinf has been defined in math.h */ /* define isnan and isinf for ANSI C, if in C99 or above, isnan and isinf has been defined in math.h */
#ifndef isinf #ifndef isinf
@ -121,11 +130,11 @@ CJSON_PUBLIC(char *) cJSON_GetStringValue(const cJSON * const item)
return item->valuestring; return item->valuestring;
} }
CJSON_PUBLIC(double) cJSON_GetNumberValue(const cJSON * const item) CJSON_PUBLIC(cJSON_float) cJSON_GetNumberValue(const cJSON * const item)
{ {
if (!cJSON_IsNumber(item)) if (!cJSON_IsNumber(item))
{ {
return (double) NAN; return (cJSON_float) NAN;
} }
return item->valuedouble; return item->valuedouble;
@ -319,7 +328,7 @@ typedef struct
/* Parse the input text to generate a number, and populate the result into item. */ /* Parse the input text to generate a number, and populate the result into item. */
static cJSON_bool parse_number(cJSON * const item, parse_buffer * const input_buffer) static cJSON_bool parse_number(cJSON * const item, parse_buffer * const input_buffer)
{ {
double number = 0; cJSON_float number;
cJSON_bool is_integer = cJSON_True; cJSON_bool is_integer = cJSON_True;
unsigned char *after_end = NULL; unsigned char *after_end = NULL;
unsigned char number_c_string[64]; unsigned char number_c_string[64];
@ -371,7 +380,7 @@ static cJSON_bool parse_number(cJSON * const item, parse_buffer * const input_bu
loop_end: loop_end:
number_c_string[i] = '\0'; number_c_string[i] = '\0';
number = strtod((const char*)number_c_string, (char**)&after_end); number = strtofloat((const char*)number_c_string, (char**)&after_end);
if (number_c_string == after_end) if (number_c_string == after_end)
{ {
return false; /* parse_error */ return false; /* parse_error */
@ -381,11 +390,11 @@ loop_end:
/* use saturation in case of overflow */ /* use saturation in case of overflow */
/* note that even float has range beyond long long (though inexactly) */ /* note that even float has range beyond long long (though inexactly) */
if (number >= (double)CJSON_INT_MAX) if (number >= (cJSON_float)CJSON_INT_MAX)
{ {
item->valueint = CJSON_INT_MAX; item->valueint = CJSON_INT_MAX;
} }
else if (number <= (double)CJSON_INT_MIN) else if (number <= (cJSON_float)CJSON_INT_MIN)
{ {
item->valueint = CJSON_INT_MIN; item->valueint = CJSON_INT_MIN;
} }
@ -406,19 +415,19 @@ loop_end:
} }
/* don't ask me, but the original cJSON_SetNumberValue returns an integer or double */ /* don't ask me, but the original cJSON_SetNumberValue returns an integer or double */
CJSON_PUBLIC(double) cJSON_SetNumberHelper(cJSON *object, double number) CJSON_PUBLIC(cJSON_float) cJSON_SetNumberHelper(cJSON *object, cJSON_float number)
{ {
if (number >= (double)CJSON_INT_MAX) if (number >= (cJSON_float)CJSON_INT_MAX)
{ {
object->valueint = CJSON_INT_MAX; object->valueint = CJSON_INT_MAX;
} }
else if (number <= (double)CJSON_INT_MIN) else if (number <= (cJSON_float)CJSON_INT_MIN)
{ {
object->valueint = CJSON_INT_MIN; object->valueint = CJSON_INT_MIN;
} }
else else
{ {
object->valueint = (int)number; object->valueint = (cJSON_int)number;
} }
return object->valuedouble = number; return object->valuedouble = number;
@ -562,22 +571,31 @@ static void update_offset(printbuffer * const buffer)
} }
/* securely comparison of floating-point variables */ /* securely comparison of floating-point variables */
static cJSON_bool compare_double(double a, double b) #ifdef CJSON_FLOAT_USE_FLOAT
static cJSON_bool compare_cJSON_float(float a, float b)
{
float maxVal = fabsf(a) > fabsf(b) ? fabsf(a) : fabsf(b);
return (fabsf(a - b) <= maxVal * FLT_EPSILON);
}
#else
static cJSON_bool compare_cJSON_float(double a, double b)
{ {
double maxVal = fabs(a) > fabs(b) ? fabs(a) : fabs(b); double maxVal = fabs(a) > fabs(b) ? fabs(a) : fabs(b);
return (fabs(a - b) <= maxVal * DBL_EPSILON); return (fabs(a - b) <= maxVal * DBL_EPSILON);
} }
#endif
/* Render the number nicely from the given item into a string. */ /* Render the number nicely from the given item into a string. */
static cJSON_bool print_number(const cJSON * const item, printbuffer * const output_buffer) static cJSON_bool print_number(const cJSON * const item, printbuffer * const output_buffer)
{ {
unsigned char *output_pointer = NULL; unsigned char *output_pointer = NULL;
double d = item->valuedouble; cJSON_float d = item->valuedouble;
int length = 0; int length = 0;
size_t i = 0; size_t i = 0;
unsigned char number_buffer[26] = {0}; /* temporary buffer to print the number into */ unsigned char number_buffer[26] = {0}; /* temporary buffer to print the number into */
unsigned char decimal_point = get_decimal_point(); unsigned char decimal_point = get_decimal_point();
double test = 0.0; cJSON_float test;
char *test_endptr = NULL;
if (output_buffer == NULL) if (output_buffer == NULL)
{ {
@ -590,20 +608,21 @@ static cJSON_bool print_number(const cJSON * const item, printbuffer * const out
length = sprintf((char*)number_buffer, "null"); length = sprintf((char*)number_buffer, "null");
} }
else if (has_no_decimals(d) && item->valueint != CJSON_INT_MAX && else if (has_no_decimals(d) && item->valueint != CJSON_INT_MAX &&
item->valueint != CJSON_INT_MIN && d == (double)item->valueint) item->valueint != CJSON_INT_MIN && d == (cJSON_float)item->valueint)
{ {
length = sprintf((char*)number_buffer, intfmt, item->valueint); length = sprintf((char*)number_buffer, intfmt, item->valueint);
} }
else else
{ {
/* Try 15 decimal places of precision to avoid nonsignificant nonzero digits */ /* Try 15 (6) decimal places of precision to avoid nonsignificant nonzero digits */
length = sprintf((char*)number_buffer, "%1.15g", d); length = sprintf((char*)number_buffer, floatfmt_shorter, d);
/* Check whether the original double can be recovered */ /* Check whether the original double can be recovered */
if ((sscanf((char*)number_buffer, "%lg", &test) != 1) || !compare_double((double)test, d)) test = strtofloat((char*)number_buffer, &test_endptr);
if (test_endptr == NULL || test_endptr == (char *)number_buffer || *test_endptr != '\0' || !compare_cJSON_float((cJSON_float)test, d))
{ {
/* If not, print with 17 decimal places of precision */ /* If not, print with 17 (9) decimal places of precision */
length = sprintf((char*)number_buffer, "%1.17g", d); length = sprintf((char*)number_buffer, floatfmt_longer, d);
} }
} }
@ -2152,7 +2171,7 @@ CJSON_PUBLIC(cJSON*) cJSON_AddBoolToObject(cJSON * const object, const char * co
return NULL; return NULL;
} }
CJSON_PUBLIC(cJSON*) cJSON_AddNumberToObject(cJSON * const object, const char * const name, const double number) CJSON_PUBLIC(cJSON*) cJSON_AddNumberToObject(cJSON * const object, const char * const name, const cJSON_float number)
{ {
cJSON *number_item = cJSON_CreateNumber(number); cJSON *number_item = cJSON_CreateNumber(number);
if (add_item_to_object(object, name, number_item, &global_hooks, false)) if (add_item_to_object(object, name, number_item, &global_hooks, false))
@ -2466,7 +2485,7 @@ CJSON_PUBLIC(cJSON *) cJSON_CreateInt(cJSON_int num)
return item; return item;
} }
CJSON_PUBLIC(cJSON *) cJSON_CreateNumber(double num) CJSON_PUBLIC(cJSON *) cJSON_CreateNumber(cJSON_float num)
{ {
cJSON *item = cJSON_New_Item(&global_hooks); cJSON *item = cJSON_New_Item(&global_hooks);
if(item) if(item)
@ -2584,7 +2603,7 @@ CJSON_PUBLIC(cJSON *) cJSON_CreateIntArray(const int *numbers, int count)
for(i = 0; a && (i < (size_t)count); i++) for(i = 0; a && (i < (size_t)count); i++)
{ {
n = cJSON_CreateNumber(numbers[i]); n = cJSON_CreateInt(numbers[i]);
if (!n) if (!n)
{ {
cJSON_Delete(a); cJSON_Delete(a);
@ -2624,7 +2643,7 @@ CJSON_PUBLIC(cJSON *) cJSON_CreateFloatArray(const float *numbers, int count)
for(i = 0; a && (i < (size_t)count); i++) for(i = 0; a && (i < (size_t)count); i++)
{ {
n = cJSON_CreateNumber((double)numbers[i]); n = cJSON_CreateNumber((cJSON_float)numbers[i]);
if(!n) if(!n)
{ {
cJSON_Delete(a); cJSON_Delete(a);
@ -2664,7 +2683,7 @@ CJSON_PUBLIC(cJSON *) cJSON_CreateDoubleArray(const double *numbers, int count)
for(i = 0; a && (i < (size_t)count); i++) for(i = 0; a && (i < (size_t)count); i++)
{ {
n = cJSON_CreateNumber(numbers[i]); n = cJSON_CreateNumber((cJSON_float)numbers[i]);
if(!n) if(!n)
{ {
cJSON_Delete(a); cJSON_Delete(a);
@ -3048,7 +3067,7 @@ CJSON_PUBLIC(cJSON_bool) cJSON_Compare(const cJSON * const a, const cJSON * cons
return true; return true;
case cJSON_Number: case cJSON_Number:
if ((a->valueint == b->valueint) && compare_double(a->valuedouble, b->valuedouble)) if ((a->valueint == b->valueint) && compare_cJSON_float(a->valuedouble, b->valuedouble))
{ {
return true; return true;
} }

20
cJSON.h
View File

@ -110,6 +110,14 @@ typedef long long cJSON_int;
typedef int cJSON_int; typedef int cJSON_int;
#endif #endif
#define notCJSON_FLOAT_USE_FLOAT
#ifdef CJSON_FLOAT_USE_FLOAT
typedef float cJSON_float;
#else
typedef double cJSON_float;
#endif
/* The cJSON structure: */ /* The cJSON structure: */
typedef struct cJSON typedef struct cJSON
{ {
@ -127,7 +135,7 @@ typedef struct cJSON
/* writing to valueint is DEPRECATED, use cJSON_SetNumberValue instead */ /* writing to valueint is DEPRECATED, use cJSON_SetNumberValue instead */
cJSON_int valueint; cJSON_int valueint;
/* The item's number, if type==cJSON_Number */ /* The item's number, if type==cJSON_Number */
double valuedouble; cJSON_float valuedouble;
/* The item's name string, if this item is the child of, or is in the list of subitems of an object. */ /* The item's name string, if this item is the child of, or is in the list of subitems of an object. */
char *string; char *string;
@ -188,7 +196,7 @@ CJSON_PUBLIC(const char *) cJSON_GetErrorPtr(void);
/* Check item type and return its value */ /* Check item type and return its value */
CJSON_PUBLIC(char *) cJSON_GetStringValue(const cJSON * const item); CJSON_PUBLIC(char *) cJSON_GetStringValue(const cJSON * const item);
CJSON_PUBLIC(double) cJSON_GetNumberValue(const cJSON * const item); CJSON_PUBLIC(cJSON_float) cJSON_GetNumberValue(const cJSON * const item);
/* These functions check the type of an item */ /* These functions check the type of an item */
CJSON_PUBLIC(cJSON_bool) cJSON_IsInvalid(const cJSON * const item); CJSON_PUBLIC(cJSON_bool) cJSON_IsInvalid(const cJSON * const item);
@ -208,7 +216,7 @@ CJSON_PUBLIC(cJSON *) cJSON_CreateTrue(void);
CJSON_PUBLIC(cJSON *) cJSON_CreateFalse(void); CJSON_PUBLIC(cJSON *) cJSON_CreateFalse(void);
CJSON_PUBLIC(cJSON *) cJSON_CreateBool(cJSON_bool boolean); CJSON_PUBLIC(cJSON *) cJSON_CreateBool(cJSON_bool boolean);
CJSON_PUBLIC(cJSON *) cJSON_CreateInt(cJSON_int num); CJSON_PUBLIC(cJSON *) cJSON_CreateInt(cJSON_int num);
CJSON_PUBLIC(cJSON *) cJSON_CreateNumber(double num); CJSON_PUBLIC(cJSON *) cJSON_CreateNumber(cJSON_float num);
CJSON_PUBLIC(cJSON *) cJSON_CreateString(const char *string); CJSON_PUBLIC(cJSON *) cJSON_CreateString(const char *string);
/* raw json */ /* raw json */
CJSON_PUBLIC(cJSON *) cJSON_CreateRaw(const char *raw); CJSON_PUBLIC(cJSON *) cJSON_CreateRaw(const char *raw);
@ -277,7 +285,7 @@ CJSON_PUBLIC(cJSON*) cJSON_AddNullToObject(cJSON * const object, const char * co
CJSON_PUBLIC(cJSON*) cJSON_AddTrueToObject(cJSON * const object, const char * const name); CJSON_PUBLIC(cJSON*) cJSON_AddTrueToObject(cJSON * const object, const char * const name);
CJSON_PUBLIC(cJSON*) cJSON_AddFalseToObject(cJSON * const object, const char * const name); CJSON_PUBLIC(cJSON*) cJSON_AddFalseToObject(cJSON * const object, const char * const name);
CJSON_PUBLIC(cJSON*) cJSON_AddBoolToObject(cJSON * const object, const char * const name, const cJSON_bool boolean); CJSON_PUBLIC(cJSON*) cJSON_AddBoolToObject(cJSON * const object, const char * const name, const cJSON_bool boolean);
CJSON_PUBLIC(cJSON*) cJSON_AddNumberToObject(cJSON * const object, const char * const name, const double number); CJSON_PUBLIC(cJSON*) cJSON_AddNumberToObject(cJSON * const object, const char * const name, const cJSON_float number);
CJSON_PUBLIC(cJSON*) cJSON_AddStringToObject(cJSON * const object, const char * const name, const char * const string); CJSON_PUBLIC(cJSON*) cJSON_AddStringToObject(cJSON * const object, const char * const name, const char * const string);
CJSON_PUBLIC(cJSON*) cJSON_AddRawToObject(cJSON * const object, const char * const name, const char * const raw); CJSON_PUBLIC(cJSON*) cJSON_AddRawToObject(cJSON * const object, const char * const name, const char * const raw);
CJSON_PUBLIC(cJSON*) cJSON_AddObjectToObject(cJSON * const object, const char * const name); CJSON_PUBLIC(cJSON*) cJSON_AddObjectToObject(cJSON * const object, const char * const name);
@ -286,8 +294,8 @@ CJSON_PUBLIC(cJSON*) cJSON_AddArrayToObject(cJSON * const object, const char * c
/* When assigning an integer value, it needs to be propagated to valuedouble too. */ /* When assigning an integer value, it needs to be propagated to valuedouble too. */
#define cJSON_SetIntValue(object, number) ((object) ? ((object)->valuedouble = (number), (object)->valueint = (number)) : (number)) #define cJSON_SetIntValue(object, number) ((object) ? ((object)->valuedouble = (number), (object)->valueint = (number)) : (number))
/* helper for the cJSON_SetNumberValue macro */ /* helper for the cJSON_SetNumberValue macro */
CJSON_PUBLIC(double) cJSON_SetNumberHelper(cJSON *object, double number); CJSON_PUBLIC(cJSON_float) cJSON_SetNumberHelper(cJSON *object, cJSON_float number);
#define cJSON_SetNumberValue(object, number) ((object != NULL) ? cJSON_SetNumberHelper(object, (double)number) : (number)) #define cJSON_SetNumberValue(object, number) ((object != NULL) ? cJSON_SetNumberHelper(object, (cJSON_float)number) : (number))
/* Change the valuestring of a cJSON_String object, only takes effect when type of object is cJSON_String */ /* Change the valuestring of a cJSON_String object, only takes effect when type of object is cJSON_String */
CJSON_PUBLIC(char*) cJSON_SetValuestring(cJSON *object, const char *valuestring); CJSON_PUBLIC(char*) cJSON_SetValuestring(cJSON *object, const char *valuestring);

View File

@ -202,7 +202,7 @@ static int supports_full_hd(const char * const monitor)
goto end; goto end;
} }
if (compare_double(width->valuedouble, 1920) && compare_double(height->valuedouble, 1080)) if (compare_cJSON_float(width->valuedouble, 1920) && compare_cJSON_float(height->valuedouble, 1080))
{ {
status = 1; status = 1;
goto end; goto end;