poke-devel
[Top][All Lists]
Advanced

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

Re: [PATCH] pkl,std: add `format_f32' and `format_f64' std functions


From: Jose E. Marchesi
Subject: Re: [PATCH] pkl,std: add `format_f32' and `format_f64' std functions
Date: Sun, 08 Jan 2023 00:21:28 +0100
User-agent: Gnus/5.13 (Gnus v5.13) Emacs/28.0.50 (gnu/linux)

Hi Mohammad.

> This commit adds two new library functions to create string
> representation of single/double-precision floating-point numbers
> from uint<32>/uint<64>.

Wouldn't it be better to add support for %f, %e and %g to `format' and
`printf' instead of having these library functions?

>
> 2022-01-07  Mohammad-Reza Nabipoor  <mnabipoor@gnu.org>
>
>       * libpoke/pkl-insn.def (formatf32): Add new instruction.
>       (formatf64): Likewise.
>       * libpoke/pvm.jitter (FORMATF): New macro for formatting
>       floating-point numbers.
>       (formatf32): New instruction for formatting floating-point
>       numbers.
>       (formatf64): Likewise.
>       * libpoke/std.pk (format_f32): Add new function for getting the
>       floating-point representation of a uint<32> number.
>       (format_f64): Likewise.
>       * doc/poke.texi (Conversion Functions): Add new section for
>       `format_f32' and `format_f64' functions.
>       * testsuite/poke.std/std-test.pk: Add two new entries for testing
>       `format_f32' and `format_f64' functions.
> ---
>  ChangeLog                      | 17 ++++++++
>  doc/poke.texi                  | 42 +++++++++++++++++++
>  libpoke/pkl-insn.def           |  2 +
>  libpoke/pvm.jitter             | 77 ++++++++++++++++++++++++++++++++++
>  libpoke/std.pk                 | 38 +++++++++++++++++
>  testsuite/poke.std/std-test.pk | 31 ++++++++++++++
>  6 files changed, 207 insertions(+)
>
> diff --git a/ChangeLog b/ChangeLog
> index 33cc53cb..2a35968c 100644
> --- a/ChangeLog
> +++ b/ChangeLog
> @@ -1,3 +1,20 @@
> +2022-01-07  Mohammad-Reza Nabipoor  <mnabipoor@gnu.org>
> +
> +     * libpoke/pkl-insn.def (formatf32): Add new instruction.
> +     (formatf64): Likewise.
> +     * libpoke/pvm.jitter (FORMATF): New macro for formatting
> +     floating-point numbers.
> +     (formatf32): New instruction for formatting floating-point
> +     numbers.
> +     (formatf64): Likewise.
> +     * libpoke/std.pk (format_f32): Add new function for getting the
> +     floating-point representation of a uint<32> number.
> +     (format_f64): Likewise.
> +     * doc/poke.texi (Conversion Functions): Add new section for
> +     `format_f32' and `format_f64' functions.
> +     * testsuite/poke.std/std-test.pk: Add two new entries for testing
> +     `format_f32' and `format_f64' functions.
> +
>  2022-01-07  Mohammad-Reza Nabipoor  <mnabipoor@gnu.org>
>  
>       * pickles/pcap.pk (PCAP_Packet): Declare body as a byte array.
> diff --git a/doc/poke.texi b/doc/poke.texi
> index b8512c91..a6bbbca3 100644
> --- a/doc/poke.texi
> +++ b/doc/poke.texi
> @@ -15122,6 +15122,8 @@ useful conversions.
>  * stoca::            filling character arrays from strings.
>  * atoi::             converting strings to integers.
>  * ltos::             converting integers to strings.
> +* format_f32::               string representation of single-precision 
> floating-points.
> +* format_f64::               string representation of double-precision 
> floating-points.
>  @end menu
>  
>  @node catos
> @@ -15212,6 +15214,46 @@ fun ltos = (long @var{i}, uint @var{base} = 10) 
> string:
>  where @var{i} is the number for which to calculate the printed
>  representation, and @var{base} is a number between 0 and 16.
>  
> +@node format_f32
> +@subsection @code{format_f32}
> +@cindex @code{format_f32}
> +
> +The @code{format_f32} standard function interpret a given unsigned
> +integer as a single-precision floating-point number and then convert
> +that number to string.  It has the following prototype:
> +
> +@example
> +fun format_f32 = (uint<32> @var{number},
> +                  uint<8> @var{precision},
> +                  uint<8> @var{style} = 'f') string:
> +@end example
> +
> +@noindent
> +where @var{number} is the floating-point number, @var{precision} is
> +exactly like what documented in manual of @code{printf} C library
> +function.  The @var{style} can be one the following characters:
> +@code{'f'}, @code{'e'} and @code{'g'}, which are behave similar to
> +@code{"%f"}, @code{"%e"} and @code{"%g"} format specifiers in
> +@code{printf} C function,
> +
> +@node format_f64
> +@subsection @code{format_f64}
> +@cindex @code{format_f64}
> +
> +The @code{format_f64} standard function interpret a given unsigned
> +integer as a double-precision floating-point number and then convert
> +that number to string.  It has the following prototype:
> +
> +@example
> +fun format_f64 = (uint<64> @var{number},
> +                  uint<8> @var{precision},
> +                  uint<8> @var{style} = 'f') string:
> +@end example
> +
> +@noindent
> +which behaves like @code{format_f32} function, except that it accepts
> +64-bit wide numbers.
> +
>  @node Array Functions
>  @section Array Functions
>  @cindex array functions
> diff --git a/libpoke/pkl-insn.def b/libpoke/pkl-insn.def
> index c9cf639b..15ba53a2 100644
> --- a/libpoke/pkl-insn.def
> +++ b/libpoke/pkl-insn.def
> @@ -252,6 +252,8 @@ PKL_DEF_INSN(PKL_INSN_FORMATI,"n","formati")
>  PKL_DEF_INSN(PKL_INSN_FORMATIU,"n","formatiu")
>  PKL_DEF_INSN(PKL_INSN_FORMATL,"n","formatl")
>  PKL_DEF_INSN(PKL_INSN_FORMATLU,"n","formatlu")
> +PKL_DEF_INSN(PKL_INSN_FORMATF32,"n","formatf32")
> +PKL_DEF_INSN(PKL_INSN_FORMATF64,"n","formatf64")
>  
>  /* Offset instructions.  */
>  
> diff --git a/libpoke/pvm.jitter b/libpoke/pvm.jitter
> index cc0f573d..20419edd 100644
> --- a/libpoke/pvm.jitter
> +++ b/libpoke/pvm.jitter
> @@ -875,6 +875,27 @@ late-header-c
>      JITTER_PUSH_STACK (pvm_make_string ((OUT)));                            \
>    } while (0)
>  
> +#define FORMATF(RESULT,NUM,PREC,STYLE,TYPEF)                                \
> +  do                                                                        \
> +    {                                                                       \
> +      static const char STYLES[] = { 'f', 'e', 'g' };                       \
> +      TYPEF x;                                                              \
> +      int n;                                                                \
> +      char fmt[16];                                                         \
> +                                                                            \
> +      PVM_ASSERT (sizeof (x) == sizeof (NUM));                              \
> +      PVM_ASSERT ((STYLE) < 3);                                             \
> +                                                                            \
> +      memcpy (&x, &(NUM), sizeof (NUM));                                    \
> +      n = snprintf (fmt, sizeof (fmt), "%%.%u%c", (unsigned)(PREC),         \
> +                    STYLES[(STYLE) % 3]);                                   \
> +      if (n == -1)                                                          \
> +        PVM_RAISE_DFL (PVM_E_CONV);                                         \
> +      n = asprintf (&(RESULT), fmt, x);                                     \
> +      if (n == -1)                                                          \
> +        PVM_RAISE_DFL (PVM_E_CONV);                                         \
> +    }                                                                       \
> +  while (0)
>    end
>  end
>  
> @@ -2399,6 +2420,62 @@ instruction formatlu (?n)
>    end
>  end
>  
> +# Instruction: formatf32
> +#
> +# Given a UINT (that should be interpreted as a 32-bit floating-point
> +# number), and a UINT (as the conversion precision), push the string
> +# representation of the floating-point number with specified precision.
> +# The formatting style is given by a literal parameters.
> +#
> +# Style 0  <=>  %f in printf
> +# Style 1  <=>  %e in printf
> +# Style 2  <=>  %g in printf
> +#
> +# Stack: ( UINT UINT -- STR )
> +
> +instruction formatf32 (?n)
> +  branching # because of PVM_RAISE_DIRECT
> +  code
> +    char *result = NULL;
> +    uint32_t num = PVM_VAL_UINT (JITTER_TOP_STACK ());
> +    unsigned style = (unsigned)JITTER_ARGN0;
> +    uint32_t precision = PVM_VAL_UINT (JITTER_UNDER_TOP_STACK ());
> +
> +    JITTER_DROP_STACK ();
> +    FORMATF (result, num, precision, style, float);
> +    JITTER_TOP_STACK () = pvm_make_string (result);
> +    free (result);
> +  end
> +end
> +
> +# Instruction: formatf64
> +#
> +# Given a ULONG (that should be interpreted as a 64-bit floating-point
> +# number), and a UINT (as the conversion precision), push the string
> +# representation of the floating-point number with specified precision.
> +# The formatting style is given by a literal parameters.
> +#
> +# Style 0  <=>  %f in printf
> +# Style 1  <=>  %e in printf
> +# Style 2  <=>  %g in printf
> +#
> +# Stack: ( ULONG UINT -- STR )
> +
> +instruction formatf64 (?n)
> +  branching # because of PVM_RAISE_DIRECT
> +  code
> +    char *result = NULL;
> +    uint64_t num = PVM_VAL_ULONG (JITTER_TOP_STACK ());
> +    unsigned style = (unsigned)JITTER_ARGN0;
> +    uint32_t precision = PVM_VAL_UINT (JITTER_UNDER_TOP_STACK ());
> +
> +    JITTER_DROP_STACK ();
> +    FORMATF (result, num, precision, style, double);
> +    JITTER_TOP_STACK () = pvm_make_string (result);
> +    free (result);
> +  end
> +end
> +
>  
>  ## Main stack manipulation instructions
>  
> diff --git a/libpoke/std.pk b/libpoke/std.pk
> index ab11160d..2dbc1804 100644
> --- a/libpoke/std.pk
> +++ b/libpoke/std.pk
> @@ -494,3 +494,41 @@ fun with_cur_ios = (int<32> ios,
>      raise exc;
>    }
>  }
> +
> +/* Create string representation of the single-precision floating-point
> +   number given as NUMBER.
> +
> +   This function supports three style of conversion to floating-points
> +   similar to %f, %e and %g format specifiers of C printf library.  */
> +
> +fun format_f32 = (uint<32> number,
> +                  uint<8> precision = 7,
> +                  uint<8> style = 'f') string:
> +  {
> +    assert (style in ['f', 'e', 'g'], "invalid formatting style");
> +
> +    var prec = precision as uint<32>;
> +
> +    return style == 'f' ? asm string: ("formatf32 0" : prec, number)
> +         : style == 'e' ? asm string: ("formatf32 1" : prec, number)
> +         : asm string: ("formatf32 2" : prec, number);
> +  }
> +
> +/* Create string representation of the double-precision floating-point
> +   number given as NUMBER.
> +
> +   This function supports three style of conversion to floating-points
> +   similar to %f, %e and %g format specifiers of C printf library.  */
> +
> +fun format_f64 = (uint<64> number,
> +                  uint<8> precision = 7,
> +                  uint<8> style = 'f') string:
> +  {
> +    assert (style in ['f', 'e', 'g'], "invalid formatting style");
> +
> +    var prec = precision as uint<32>;
> +
> +    return style == 'f' ? asm string: ("formatf64 0" : prec, number)
> +         : style == 'e' ? asm string: ("formatf64 1" : prec, number)
> +         : asm string: ("formatf64 2" : prec, number);
> +  }
> diff --git a/testsuite/poke.std/std-test.pk b/testsuite/poke.std/std-test.pk
> index edf44dbf..a531934f 100644
> --- a/testsuite/poke.std/std-test.pk
> +++ b/testsuite/poke.std/std-test.pk
> @@ -295,6 +295,37 @@ var tests = [
>          qsort ([4,3,2,1], cmpints);
>        },
>    },
> +  PkTest {
> +    name = "format_f32",
> +    func = lambda (string name) void:
> +      {
> +        assert (format_f32 (0x4048f5c3U) == "3.1400001");
> +        assert (format_f32 (0x4048f5c3U, 7) == "3.1400001");
> +        assert (format_f32 (0x4048f5c3U, 7, 'f') == "3.1400001");
> +        assert (format_f32 (0x4048f5c3U, 9) == "3.140000105");
> +        assert (format_f32 (0x4048f5c3U, 22) == "3.1400001049041748046875");
> +        assert (format_f32 (0x4048f5c3U, 22, 'e')
> +                == "3.1400001049041748046875e+00");
> +        assert ((format_f32 :number 0x4048f5c3U :style 'g') == "3.14");
> +        assert ((format_f32 :number 0x4048f5c3U :style 'g' :precision 8)
> +                == "3.1400001");
> +      },
> +  },
> +  PkTest {
> +    name = "format_f64",
> +    func = lambda (string name) void:
> +      {
> +        assert (format_f64 (0x40091eb851eb851fU) == "3.1400000");
> +        assert (format_f64 (0x40091eb851eb851fU, 7) == "3.1400000");
> +        assert (format_f64 (0x40091eb851eb851fU, 7, 'f') == "3.1400000");
> +        assert (format_f64 (0x40091eb851eb851fU, 14) == "3.14000000000000");
> +        assert (format_f64 (0x40091eb851eb851fU, 15, 'e')
> +                == "3.140000000000000e+00");
> +        assert (format_f64 (0x40091eb851eb851fU, 15, 'g') == "3.14");
> +        assert (format_f64 (0x40091eb851eb851fU, 51)
> +                == "3.140000000000000124344978758017532527446746826171875");
> +      },
> +  },
>  ];
>  
>  exit (pktest_run (tests) ? 0 : 1);



reply via email to

[Prev in Thread] Current Thread [Next in Thread]