NetBSD Problem Report #36770

From martin@duskware.de  Fri Aug 10 21:40:50 2007
Return-Path: <martin@duskware.de>
Received: from mail.netbsd.org (mail.netbsd.org [204.152.190.11])
	by narn.NetBSD.org (Postfix) with ESMTP id CFA4063B8EA
	for <gnats-bugs@gnats.netbsd.org>; Fri, 10 Aug 2007 21:40:49 +0000 (UTC)
Message-Id: <20070810203346.809BB63B8EA@narn.NetBSD.org>
Date: Fri, 10 Aug 2007 20:33:46 +0000 (UTC)
From: M.Drochner@fz-juelich.de
Reply-To: M.Drochner@fz-juelich.de
To: netbsd-bugs-owner@NetBSD.org
Subject: "long double" arithmetics doesn't work on i386
X-Send-Pr-Version: www-1.0

>Number:         36770
>Category:       port-i386
>Synopsis:       "long double" arithmetics doesn't work on i386
>Confidential:   no
>Severity:       serious
>Priority:       medium
>Responsible:    port-i386-maintainer
>State:          open
>Class:          sw-bug
>Submitter-Id:   net
>Arrival-Date:   Fri Aug 10 21:45:00 +0000 2007
>Last-Modified:  Thu Aug 16 21:10:02 +0000 2007
>Originator:     Matthias Drochner
>Release:        current/i386
>Organization:
>Environment:
gcc version 4.1.3 20070620 prerelease (NetBSD nb1 20070620)
>Description:
This seems to be a toolchain issue.
Appearently, gcc fails to emit instuctions which set the i387
floating point control word to 64-bit rounding where "long double"
data types are used. This makes that 53-bit rounding is used which
is the default on NetBSD (for good reasons afaiu).
So one doesn't get additional precision from the use of "long double".

>How-To-Repeat:
Try the program below (taken from an sqlite3 selftest).
"xxx" implements a poor man's atof(); while it doesn't do proper
rounding the use of "long double" internally should make that
the "double" result is correct anyway (as is the result of atof(),
for comparision).
Setting the FPCW, as done in the "#ifdef FIX" part, makes that
the result is correct. This should be done by gcc automatically.


#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>

double
xxx(const char *s)
{
        long double r = 0.0;

#ifdef FIX
        const int fpcw = 0x37f;
        asm("fldcw %0"::"m"(fpcw));
#endif

        while (isdigit(*s)) {
                r = r * 10.0 + (*s - '0');
                s++;
        }
        return r;
}

main()
{
        const char in[] = "9223372036854774800";
        double f = xxx(in);
        double g = atof(in);
        printf("%s %.20g %.20g\n", in, f, g);
}

>Fix:
For now I can only tell that setting TARGET_96_ROUND_53_LONG_DOUBLE
in the gcc configuration doesn't help.

>Audit-Trail:
From: Matthias Drochner <M.Drochner@fz-juelich.de>
To: gnats-bugs@NetBSD.org
Cc: port-i386-maintainer@NetBSD.org, gnats-admin@NetBSD.org,
	netbsd-bugs@NetBSD.org
Subject: Re: port-i386/36770: "long double" arithmetics doesn't work on i386

Date: Mon, 13 Aug 2007 15:48:59 +0200

 M.Drochner@fz-juelich.de said:
 > gcc fails to emit instuctions which set the i387 floating point
 > control word to 64-bit rounding where "long double" data types are
 > used

 After some research I came to the conclusion that gcc doesn't
 intend to do so. (It might kill performance anyway.)
 It does instead live with the fact that the FPU does only
 provide IEEE "double" accuracy, even with "long double"
 variables. Since the standards (ISO C and IEEE754) do not
 require that "long double" is any better that "double", this
 is legal.

 > setting TARGET_96_ROUND_53_LONG_DOUBLE
 > in the gcc configuration doesn't help

 What this does is to dumb down compile time calculations
 on "long double" types to use 53-bit accuracy (while using
 the 80/96-bit format where data are put to .data).
 So this should be set for NetBSD/i386 (and amd64) for
 consistency between compile-time and runtime calculations,
 otherwise we might see different behaviour depending on
 eg optimization levels.

 > Try the program below (taken from an sqlite3 selftest).

 sqlite3's assumption that use of "long double" will fix
 the flaws of the conversion algorithm is not portable.
 I've filed a bug report there (#2570).

 This further means for NetBSD/i386:
 -Use of "long double" is just a waste of memory, and memory
  bandwidth.
 +It is almost as easy to implement expl(), logl() and all the other
  "long double" variants of math functions on i386 as it is for
  platforms where "long double" is identical to "double": just
  use wrappers which convert arguments, no need to implement
  algorithms which provide higher accuracies.

 best regards
 Matthias


 Forschungszentrum Juelich GmbH
 52425 Juelich

 Sitz der Gesellschaft: Juelich
 Eingetragen im Handelsregister des Amtsgerichts Dueren Nr. HR B 3498
 Vorsitzende des Aufsichtsrats: MinDirig'in Baerbel Brumme-Bothe
 Vorstand: Prof. Dr. Achim Bachem (Vorsitzender), Dr. Ulrich Krafft (stellv. 
 Vorsitzender)

From: Matthias Drochner <M.Drochner@fz-juelich.de>
To: M.Drochner@fz-juelich.de
Cc: gnats-bugs@NetBSD.org, port-i386-maintainer@NetBSD.org,
	gnats-admin@NetBSD.org, netbsd-bugs@NetBSD.org
Subject: Re: port-i386/36770: "long double" arithmetics doesn't work on i386

Date: Thu, 16 Aug 2007 23:06:47 +0200

 This is a multipart MIME message.

 --==_Exmh_24243496863520
 Content-Type: text/plain; charset=us-ascii


 Some more findings:

 M.Drochner@fz-juelich.de said:
 > -Use of "long double" is just a waste of memory, and memory
 >  bandwidth. 

 Almost, but not quite: while the exponent is effectively
 limited to 53 bits, the mantissa has still 15 bits which
 is 4 more than double. So there is no gain in accuracy
 but a little more dynamic range.

 > +It is almost as easy to implement expl(), logl() and all the other
 >  "long double" variants

 So, in the light of this, it is not _that_ easy because the numeric
 ranges are different. The algorithms can still be reused I think.

 Another fact is that the LDBL_* macros of <float.h> don't
 reflect reality. Eg LDBL_MAX is already infinity. The long double
 support in gdtoa also suffers from this.
 See the appended program. On an i386/current box, it gives:
 1.189731495357231765021264e+4932
 inf
 1.189731495357231765021264e+4932
 inf
 1.189731495357231599977347e+4932
 1.189731495357231632999029e+4932
 1.189731495357231599977347e+4932
 1.189731495357231632999029e+4932

 which shows that both the compiler and gdtoa don't know about the
 53-bit mantissa -- LDBL_MAX gets converted to a number which will
 cause an overflow, and the other number has some excess bits in
 the mantissa which will get lost if touched by the FPU later.

 If I set the TARGET_96_ROUND_53_LONG_DOUBLE as said in my previous mail,
 it gives:
 inf
 inf
 1.189731495357231765021264e+4932
 inf
 1.189731495357231632999029e+4932
 1.189731495357231632999029e+4932
 1.189731495357231599977347e+4932
 1.189731495357231632999029e+4932

 which shows that the constants generated at compile time are
 consistent with reality now, but gdtoa still assumes mantissa
 bits not usable for further calculations.

 Adapting the LDBL_ constants to the 53-bit mantissa should fix
 this, but some review is needed because at some points just
 mantissa lengths are compared to decide whether a "long double"
 is different from a "double".

 best regards
 Matthias





 -----------------------------------------------------------------------------------------
 -----------------------------------------------------------------------------------------
 Forschungszentrum Juelich GmbH
 52425 Juelich

 Sitz der Gesellschaft: Juelich
 Eingetragen im Handelsregister des Amtsgerichts Dueren Nr. HR B 3498
 Vorsitzende des Aufsichtsrats: MinDirig'in Baerbel Brumme-Bothe
 Vorstand: Prof. Dr. Achim Bachem (Vorsitzender), Dr. Ulrich Krafft (stellv. 
 Vorsitzender)
 -----------------------------------------------------------------------------------------
 -----------------------------------------------------------------------------------------

 --==_Exmh_24243496863520
 Content-Type: text/plain ; name="stest.c"; charset=us-ascii
 Content-Description: stest.c
 Content-Disposition: attachment; filename="stest.c"

 #include <float.h>
 #include <stdio.h>
 #include <stdlib.h>

 #define TRUE_LDBL_MAX 1.1897314953572316E+4932L
 long double null;

 void
 pr(long double d)
 {

 	printf("%.25Lg\n", d);
 	d += null;
 	printf("%.25Lg\n", d);
 }

 #define pr2(x) pr(x);pr(strtold(#x, 0))
 #define pr3(x) pr2(x)

 int
 main()
 {

 	pr3(LDBL_MAX);
 	pr3(TRUE_LDBL_MAX);

 	return 0;
 }

 --==_Exmh_24243496863520--

NetBSD Home
NetBSD PR Database Search

(Contact us) $NetBSD: query-full-pr,v 1.39 2013/11/01 18:47:49 spz Exp $
$NetBSD: gnats_config.sh,v 1.8 2006/05/07 09:23:38 tsutsui Exp $
Copyright © 1994-2007 The NetBSD Foundation, Inc. ALL RIGHTS RESERVED.