From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on inbox.vuxu.org X-Spam-Level: X-Spam-Status: No, score=-1.0 required=5.0 tests=DKIM_ADSP_CUSTOM_MED, FREEMAIL_FROM,MAILING_LIST_MULTI,RCVD_IN_DNSWL_NONE autolearn=ham autolearn_force=no version=3.4.2 Received: from primenet.com.au (ns1.primenet.com.au [203.24.36.2]) by inbox.vuxu.org (OpenSMTPD) with ESMTP id b191a0e8 for ; Sat, 21 Dec 2019 09:44:36 +0000 (UTC) Received: (qmail 22152 invoked by alias); 21 Dec 2019 09:44:30 -0000 Mailing-List: contact zsh-workers-help@zsh.org; run by ezmlm Precedence: bulk X-No-Archive: yes List-Id: Zsh Workers List List-Post: List-Help: List-Unsubscribe: X-Seq: 45106 Received: (qmail 7759 invoked by uid 1010); 21 Dec 2019 09:44:30 -0000 X-Qmail-Scanner-Diagnostics: from mail-il1-f178.google.com by f.primenet.com.au (envelope-from , uid 7791) with qmail-scanner-2.11 (clamdscan: 0.102.1/25663. spamassassin: 3.4.2. Clear:RC:0(209.85.166.178):SA:0(-2.0/5.0):. Processed in 2.294423 secs); 21 Dec 2019 09:44:30 -0000 X-Envelope-From: roman.perepelitsa@gmail.com X-Qmail-Scanner-Mime-Attachments: | X-Qmail-Scanner-Zip-Files: | Received-SPF: pass (ns1.primenet.com.au: SPF record at _netblocks.google.com designates 209.85.166.178 as permitted sender) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:mime-version:references:in-reply-to:from:date :message-id:subject:to:content-transfer-encoding; bh=Q786+DBsZNsjnCsCW5g9Oxattm18wIOrO9jKqSQndUA=; b=Jx2YPAwg/aIDEXzjomSZVK0qQ34xtezIl5T9yGyNQZKX0W0Evhw2DSLrNA8EcCEjgK 6XECR4CxBFNJ+CiexbbMRFs4JP043iZYUjBA2zV3tYf+8aQKa+XW4RZpOk8iISiqh5X4 bSb+3FdP4045faGko3gl7cOmH93Nh2I/iLWwXmddt8qDSMHc7r1evzD2uPd+pu2EJbU7 a/yF1LCbU04qKGxQ/dOMV1Q2yg0bm3U8onJt1IbOIXhtYYOLPbZ6gbxKJbtJuxhwEs+2 C90J19YgGPoVNZjMY/IZ1kkrKw8sXDcIy4zNtX5Ups4KhPdpWGqYSXcVMWF1OzJGNDhF F88g== X-Gm-Message-State: APjAAAVhFpLgykAOuIdk4nzuc+2s01tkDGXaO42eRUtja7vNaqKtmUhK Mr7WMWaWKqFLwuwmkjRAEB2folk6puH+2ltx2crTHrZ4mzc= X-Google-Smtp-Source: APXvYqyPVIZoYUiRXKuTjeg2nQaMMTTmoq+in/pC3HcwEv+ePCZpPAJtuP0hlTlZX7fE//PucBet1SR38decJpIjG8A= X-Received: by 2002:a92:290a:: with SMTP id l10mr16223119ilg.151.1576921434605; Sat, 21 Dec 2019 01:43:54 -0800 (PST) MIME-Version: 1.0 References: <20191220013711.GA708801@zira.vinc17.org> <20191220165824.ufvjtx37xt7dp2dt@chaz.gmail.com> <20191221005005.GB767822@zira.vinc17.org> <20191221084736.bokldw7tzxw3thn3@chaz.gmail.com> In-Reply-To: <20191221084736.bokldw7tzxw3thn3@chaz.gmail.com> From: Roman Perepelitsa Date: Sat, 21 Dec 2019 10:43:43 +0100 Message-ID: Subject: Re: zsh converts a floating-point number to string with too much precision To: Zsh hackers list Content-Type: text/plain; charset="UTF-8" Content-Transfer-Encoding: quoted-printable On Sat, Dec 21, 2019 at 9:48 AM Stephane Chazelas wrote: > So on a system (with a compiler) where C doubles are implemented > as IEEE 754 double precision, both 1.1 and 1.1000000000000001 > are represented as the same binary double (whose exact value is > 1.100000000000000088817841970012523233890533447265625). > > So you're saying echo $((1.1000000000000001)) and echo $((1.1)) > should output 1.1, because even though 1.1000000000000001 is > closer to that value than 1.1000000000000000, zsh should pick > the latter because people prefer to see shorter number > representations and in that case it doesn't matter which one we > pick as both lead to the same double. Correct. The best formal description of this process that I know of is the specification of to_chars() functions in the C++ standard: The functions [...] ensure that the string representation consists of the smallest number of characters such that there is at least one digit before the radix point (if present) and parsing the representation using the corresponding from_chars function recovers value exactly. [Note: This guarantee applies only if to_chars and from_chars are executed on the same implementation. =E2=80=94 end note] If there are several such representations, the representation with the smallest difference from the floating-point argument value is chosen, resolving any remaining ties using rounding according to round_to_nearest. There is no simple algorithm that achieves this. I recall reading long papers a few years back that were describing various inventions in this field. They were pretty scary. > Is there a standard C API for that? Not that I know of. FWIW, neither gcc (libstdc++) nor clang (libc++) have implemented to_chars() for floating points in the two years since it's been added to the standard (C++17). > > Or would we get the output of sprintf("%.17g"), look at the last > two significant digits, if the second last is 9 or 0, then see > if rounding it and doing a strtod again yields the same double? I believe printing the value with full precision and then truncating the string this is the most popular approach. All implementations that are faster are only marginally so, and they are much more complex. I think this approach should work well enough for zsh. Lifting this sort of implementation from another project would be ideal (someone would have to find it; my apologies for not doing it myself). Roman.