[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [tyndur-devel] [PATCH] libm: Rundungsfunktionen



On Mon, Aug 10 15:16, Kevin Wolf wrote:
> + libm: floor, ceil, round, trunc, nearbyint, fesetround, fegetround
> 
> Signed-off-by: Kevin Wolf <kevin@xxxxxxxxxx>
> ---
>  src/modules/include/math.h           |   25 ++++
>  src/modules/lib/stdlibc/math/round.c |  212 ++++++++++++++++++++++++++++++++++
>  2 files changed, 237 insertions(+), 0 deletions(-)
>  create mode 100644 src/modules/lib/stdlibc/math/round.c
> 
> diff --git a/src/modules/include/math.h b/src/modules/include/math.h
> index 49083ab..138fff3 100644
> --- a/src/modules/include/math.h
> +++ b/src/modules/include/math.h
> @@ -49,6 +49,12 @@
>  #define M_SQRT2     1.41421356237309504880
>  #define M_SQRT1_2   0.70710678118654752440
>  
> +enum {
> +    FE_TONEAREST,
> +    FE_UPWARD,
> +    FE_DOWNWARD,
> +    FE_TOWARDZERO,
> +};

Das gehört laut meinem C-Standard nach fenv.h

>  
>  
>  double      tan(double);
> @@ -94,5 +100,24 @@ double      acos(double);
>  float       acosf(float);
>  long double acosl(long double);
>  
> +
> +double      floor(double x);
> +float       floorf(float x);
> +long double floorl(long double x);
> +double      ceil(double x);
> +float       ceilf(float x);
> +long double ceill(long double x);
> +double      trunc(double x);
> +float       truncf(float x);
> +long double truncl(long double x);
> +double      round(double x);
> +float       roundf(float x);
> +long double roundl(long double x);

> +int         fegetround(void);
> +int         fesetround(int rounding_mode);
Die beiden genau so.

> +double      nearbyint(double x);
> +float       nearbyintf(float x);
> +long double nearbyintl(long double x);
> +
>  #endif
>  
> diff --git a/src/modules/lib/stdlibc/math/round.c b/src/modules/lib/stdlibc/math/round.c
> new file mode 100644
> index 0000000..b4fd618
> --- /dev/null
> +++ b/src/modules/lib/stdlibc/math/round.c
> @@ -0,0 +1,212 @@
> +/*
> + * Copyright (c) 2009 The tyndur Project. All rights reserved.
> + *
> + * This code is derived from software contributed to the tyndur Project
> + * by Kevin Wolf.
> + *
> + * Redistribution and use in source and binary forms, with or without
> + * modification, are permitted provided that the following conditions
> + * are met:
> + * 1. Redistributions of source code must retain the above copyright
> + *    notice, this list of conditions and the following disclaimer.
> + * 2. Redistributions in binary form must reproduce the above copyright
> + *    notice, this list of conditions and the following disclaimer in the
> + *    documentation and/or other materials provided with the distribution.
> + *
> + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
> + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
> + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
> + * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR
> + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
> + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
> + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
> + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
> + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
> + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
> + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
> + */
> +
> +#include <math.h>
> +#include <stdint.h>
> +#include <stdlib.h>
> +
> +#define ROUND_NEAR  "$0x000"
> +#define ROUND_DOWN  "$0x400"
> +#define ROUND_UP    "$0x800"
> +#define ROUND_TRUNC "$0xc00"
> +
> +static int rounding_mode = FE_TONEAREST;
> +
> +/*
> + * Achtung:
> + *
> + * Die folgenden Funktionen basieren auf der Annahme, dass das RC-Feld im FPU
> + * Control Word normalerweise immer auf 0 gesetzt ist, also der neue Wert durch
> + * ein einfaches or eingetragen werden kann.
> + */
> +
> +long double floorl(long double x)
> +{
> +    long double res;
> +    uint16_t control_word;
> +
> +    asm(
> +        // Rundungsmodus setzen
> +        "fnstcw %2;"
> +        "mov %2, %%eax;"
> +        "orl " ROUND_DOWN ", %2;"
> +        "fldcw %2;"
> +
> +        // Zahl auf dem Stack runden
> +        "frndint;"
> +
> +        // Wieder den Standardrundungsmodus setzen
> +        "mov %%eax, %2;"
> +        "fldcw %2;"
> +        : "=t" (res) : "0" (x), "m" (control_word) : "eax");
> +
> +    return res;
> +}
> +
> +double floor(double x)
> +{
> +    return floorl(x);
> +}
> +
> +float floorf(float x)
> +{
> +    return floorl(x);
> +}
> +
> +
> +long double ceill(long double x)
> +{
> +    long double res;
> +    uint16_t control_word;
> +
> +    asm(
> +        // Rundungsmodus setzen
> +        "fnstcw %2;"
> +        "mov %2, %%eax;"
> +        "orl " ROUND_UP ", %2;"
> +        "fldcw %2;"
> +
> +        // Zahl auf dem Stack runden
> +        "frndint;"
> +
> +        // Wieder den Standardrundungsmodus setzen
> +        "mov %%eax, %2;"
> +        "fldcw %2;"
> +        : "=t" (res) : "0" (x), "m" (control_word) : "eax");
> +

Hm könnte man floorl, ceill und truncl nicht alle in eine Funktion mit
einem Parameter fuer den Rundungsmodus packen, von mir aus auch static
inline?

> +    return res;
> +}
> +
> +double ceil(double x)
> +{
> +    return ceill(x);
> +}
> +
> +float ceilf(float x)
> +{
> +    return ceill(x);
> +}
> +
> +long double truncl(long double x)
> +{
> +    long double res;
> +    uint16_t control_word;
> +
> +    asm(
> +        // Rundungsmodus setzen
> +        "fnstcw %2;"
> +        "mov %2, %%eax;"
> +        "orl " ROUND_TRUNC ", %2;"
> +        "fldcw %2;"
> +
> +        // Zahl auf dem Stack runden
> +        "frndint;"
> +
> +        // Wieder den Standardrundungsmodus setzen
> +        "mov %%eax, %2;"
> +        "fldcw %2;"
> +        : "=t" (res) : "0" (x), "m" (control_word) : "eax");
> +
> +    return res;
> +}
> +
> +double trunc(double x)
> +{
> +    return truncl(x);
> +}
> +
> +float truncf(float x)
> +{
> +    return truncl(x);
> +}
> +
> +long double roundl(long double x)
> +{
> +    long double res;
> +
> +    asm("frndint" : "=t" (res) : "0" (x));
> +
> +    return res;
> +}
> +
> +double round(double x)
> +{
> +    return roundl(x);
> +}
> +
> +float roundf(float x)
> +{
> +    return roundl(x);
> +}
> +
> +long double nearbyintl(long double x)
> +{
> +    switch (rounding_mode) {
> +        case FE_TONEAREST:
> +            return roundl(x);
> +        case FE_TOWARDZERO:
> +            return truncl(x);
> +        case FE_DOWNWARD:
> +            return floorl(x);
> +        case FE_UPWARD:
> +            return ceill(x);
> +    }
> +
> +    abort();
> +    return x;
> +}
> +
> +double nearbyint(double x)
> +{
> +    return nearbyintl(x);
> +}
> +
> +float nearbyintf(float x)
> +{
> +    return nearbyintl(x);
> +}
> +
> +int fegetround(void)
> +{
> +    return rounding_mode;
> +}
> +
> +int fesetround(int mode)
> +{
> +    switch(mode) {
> +        case FE_TONEAREST:
> +        case FE_TOWARDZERO:
> +        case FE_DOWNWARD:
> +        case FE_UPWARD:
> +            rounding_mode = mode;
> +            return 0;
> +
> +        default:
> +            return -1;
> +    }
> +}
> -- 
> 1.6.0.2
> 
> _______________________________________________
> tyndur-devel mailing list
> tyndur-devel@xxxxxxxxxx
> http://list.tyndur.org/mailman/listinfo/tyndur-devel

-- 
Antoine Kaufmann
<toni@xxxxxxxxxxxxxxxx>

Attachment: pgphtMD2qbcZO.pgp
Description: PGP signature