poke-devel
[Top][All Lists]
Advanced

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

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


From: Mohammad-Reza Nabipoor
Subject: [PATCH] pkl,std: add `format_f32' and `format_f64' std functions
Date: Sat, 7 Jan 2023 20:49:52 +0100

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

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);
-- 
2.39.0




reply via email to

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