Giter VIP home page Giter VIP logo

Comments (4)

j4cbo avatar j4cbo commented on July 20, 2024

No, this is not a goal - json11 is designed to round-trip cleanly, not truncate on serialization. You could use a custom type for the objects that need special formatting and implement a to_json() member function, perhaps?

from json11.

wrbuaa2005 avatar wrbuaa2005 commented on July 20, 2024

Thanks. The reason I asked is that even if I used sth. like round(num * 100000) / 100000 for num = 1.233491314, this number might be stored as 1.2334900000000002 because of machine error. The only way I can think of to avoid is to convert it to string. But my colleague won't allow me since it will make the program slower.

I'll look into the way to define object of custom type.

from json11.

artwyman avatar artwyman commented on July 20, 2024

One possible workaround would be to do a hacky version of fixed-point and store your numbers in an int. E.g. if you know you always want exactly 5 decimal places, store 1.23349 as 123349. When storing data to JSON, multiply by 100000 and cast to int. When reading from JSON, cast to double and divide by 100000. This assumes you never need more than 53 bits of integer, and that you won't waste more space by giving every number the full 5 decimal places (e.g. if many of them are integers which would've truncated naturally).

from json11.

peterritter avatar peterritter commented on July 20, 2024

Hi all

I heavily modified the library for my own purposes. I never subscribed to the philosophy that a json object should not / cannot be modified after it was created so I just changed it to fit my own requirements (in many ways). I also fixed the floating point issue by including a couple libraries. Unfortunately I modified the json11 library so much that it can't be merged anymore. I also don't know how to use github. But here are the libs I used for floating point conversion - it was relatively straight forward to change. Both algorithm don't use the exact same precision, one stops at 17 digits after decimal point, the other at around 25, so roundtrip is not perfect but its good enough for me. This could maybe be adjusted somewhere but I had already spent a day on this so I just let it be.

Regards, Peter

to convert to string I used:

https://github.com/miloyip/dtoa-benchmark/blob/master/src/milo/dtoa_milo.h

to convert from string I used :

/*

  • strtod.c --
    *
  • Source code for the "strtod" library procedure.
  • Copyright (c) 1988-1993 The Regents of the University of California.
  • Copyright (c) 1994 Sun Microsystems, Inc.
    *
  • Permission to use, copy, modify, and distribute this
  • software and its documentation for any purpose and without
  • fee is hereby granted, provided that the above copyright
  • notice appear in all copies. The University of California
  • makes no representations about the suitability of this
  • software for any purpose. It is provided "as is" without
  • express or implied warranty.
    *
  • RCS: @(#) $Id$
    */

//#include "config.h"
#ifdef HAVE_STDLIB_H

include <stdlib.h>

#endif
#include <ctype.h>
#include <errno.h>
//extern int errno;

#ifndef STDC

ifdef GNUC

define const const

else

define const

endif

#endif

#ifndef TRUE
#define TRUE 1
#define FALSE 0
#endif
#ifndef NULL
#define NULL 0
#endif

static int maxExponent = 511;   /* Largest possible base 10 exponent.  Any
                 * exponent larger than this will already
                 * produce underflow or overflow, so there's
                 * no need to worry about additional digits.
                 */
static double powersOf10[] = {  /* Table giving binary powers of 10.  Entry */
    10.,            /* is 10^2^i.  Used to convert decimal */
    100.,           /* exponents into floating-point numbers. */
    1.0e4,
    1.0e8,
    1.0e16,
    1.0e32,
    1.0e64,
    1.0e128,
    1.0e256
};

/*
 *----------------------------------------------------------------------
 *
 * strtod --
 *
 *  This procedure converts a floating-point number from an ASCII
 *  decimal representation to internal double-precision format.
 *
 * Results:
 *  The return value is the double-precision floating-point
 *  representation of the characters in string.  If endPtr isn't
 *  NULL, then *endPtr is filled in with the address of the
 *  next character after the last one that was part of the
 *  floating-point number.
 *
 * Side effects:
 *  None.
 *
 *----------------------------------------------------------------------
 */

double
    strtod_alt(string, endPtr)
    const char *string;     /* A decimal ASCII floating-point number,
                 * optionally preceded by white space.
                 * Must have form "-I.FE-X", where I is the
                 * integer part of the mantissa, F is the
                 * fractional part of the mantissa, and X
                 * is the exponent.  Either of the signs
                 * may be "+", "-", or omitted.  Either I
                 * or F may be omitted, or both.  The decimal
                 * point isn't necessary unless F is present.
                 * The "E" may actually be an "e".  E and X
                 * may both be omitted (but not just one).
                 */
char **endPtr;      /* If non-NULL, store terminating character's
             * address here. */
{
    int sign, expSign = FALSE;
    double fraction, dblExp, *d;
    register const char *p;
    register int c;
    int exp = 0;        /* Exponent read from "EX" field. */
    int fracExp = 0;        /* Exponent that derives from the fractional
                 * part.  Under normal circumstatnces, it is
                 * the negative of the number of digits in F.
                 * However, if I is very long, the last digits
                 * of I get dropped (otherwise a long I with a
                 * large negative exponent could cause an
                 * unnecessary overflow on I alone).  In this
                 * case, fracExp is incremented one for each
                 * dropped digit. */
    int mantSize;       /* Number of digits in mantissa. */
    int decPt;          /* Number of mantissa digits BEFORE decimal
                 * point. */
    const char *pExp;       /* Temporarily holds location of exponent
                 * in string. */

                 /*
                  * Strip off leading blanks and check for a sign.
                  */

    p = string;
    while (isspace(*p)) {
        p += 1;
    }
    if (*p == '-') {
        sign = TRUE;
        p += 1;
    }
    else {
        if (*p == '+') {
            p += 1;
        }
        sign = FALSE;
    }

    /*
     * Count the number of digits in the mantissa (including the decimal
     * point), and also locate the decimal point.
     */

    decPt = -1;
    for (mantSize = 0; ; mantSize += 1)
    {
        c = *p;
        if (!isdigit(c)) {
            if ((c != '.') || (decPt >= 0)) {
                break;
            }
            decPt = mantSize;
        }
        p += 1;
    }

    /*
     * Now suck up the digits in the mantissa.  Use two integers to
     * collect 9 digits each (this is faster than using floating-point).
     * If the mantissa has more than 18 digits, ignore the extras, since
     * they can't affect the value anyway.
     */

    pExp = p;
    p -= mantSize;
    if (decPt < 0) {
        decPt = mantSize;
    }
    else {
        mantSize -= 1;          /* One of the digits was the point. */
    }
    if (mantSize > 18) {
        fracExp = decPt - 18;
        mantSize = 18;
    }
    else {
        fracExp = decPt - mantSize;
    }
    if (mantSize == 0) {
        fraction = 0.0;
        p = string;
        goto done;
    }
    else {
        int frac1, frac2;
        frac1 = 0;
        for (; mantSize > 9; mantSize -= 1)
        {
            c = *p;
            p += 1;
            if (c == '.') {
                c = *p;
                p += 1;
            }
            frac1 = 10 * frac1 + (c - '0');
        }
        frac2 = 0;
        for (; mantSize > 0; mantSize -= 1)
        {
            c = *p;
            p += 1;
            if (c == '.') {
                c = *p;
                p += 1;
            }
            frac2 = 10 * frac2 + (c - '0');
        }
        fraction = (1.0e9 * frac1) + frac2;
    }

    /*
     * Skim off the exponent.
     */

    p = pExp;
    if ((*p == 'E') || (*p == 'e')) {
        p += 1;
        if (*p == '-') {
            expSign = TRUE;
            p += 1;
        }
        else {
            if (*p == '+') {
                p += 1;
            }
            expSign = FALSE;
        }
        while (isdigit(*p)) {
            exp = exp * 10 + (*p - '0');
            p += 1;
        }
    }
    if (expSign) {
        exp = fracExp - exp;
    }
    else {
        exp = fracExp + exp;
    }

    /*
     * Generate a floating-point number that represents the exponent.
     * Do this by processing the exponent one bit at a time to combine
     * many powers of 2 of 10. Then combine the exponent with the
     * fraction.
     */

    if (exp < 0) {
        expSign = TRUE;
        exp = -exp;
    }
    else {
        expSign = FALSE;
    }
    if (exp > maxExponent) {
        exp = maxExponent;
        errno = ERANGE;
    }
    dblExp = 1.0;
    for (d = powersOf10; exp != 0; exp >>= 1, d += 1) {
        if (exp & 01) {
            dblExp *= *d;
        }
    }
    if (expSign) {
        fraction /= dblExp;
    }
    else {
        fraction *= dblExp;
    }

done:
    if (endPtr != NULL) {
        *endPtr = (char *)p;
    }

    if (sign) {
        return -fraction;
    }
    return fraction;
}

from json11.

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.