aboutsummaryrefslogtreecommitdiffstats
path: root/src/float
diff options
context:
space:
mode:
authorGravatar Gediminas Jakutis <gediminas@varciai.lt> 2015-01-31 20:35:30 +0200
committerGravatar Gediminas Jakutis <gediminas@varciai.lt> 2015-03-03 23:36:16 +0200
commit8b26e3ef33e3871762ebd62acbff85b2c3abd9fc (patch)
tree67d917b8694572b735662d2786fb77eac23ccaa9 /src/float
downloadlibrin-0.0.1.tar.gz
librin-0.0.1.tar.bz2
librin-0.0.1.zip
Initial commit - Release 0.0.1librin-0.0.1
Diffstat (limited to 'src/float')
-rw-r--r--src/float/Makefile.am26
-rw-r--r--src/float/float.c248
-rw-r--r--src/float/float_private.h29
3 files changed, 303 insertions, 0 deletions
diff --git a/src/float/Makefile.am b/src/float/Makefile.am
new file mode 100644
index 0000000..d8d2675
--- /dev/null
+++ b/src/float/Makefile.am
@@ -0,0 +1,26 @@
+# Copyright (C) 2015 Gediminas Jakutis
+#
+# This Makefile.am is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; version 2.1
+# of the License.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+
+AM_CFLAGS = \
+ -I$(top_srcdir)/include/ \
+ -Wall \
+ -Wextra
+
+noinst_LTLIBRARIES = librin_float.la
+
+librin_float_la_SOURCES = \
+ float.c \
+ float_private.h
diff --git a/src/float/float.c b/src/float/float.c
new file mode 100644
index 0000000..97fcb41
--- /dev/null
+++ b/src/float/float.c
@@ -0,0 +1,248 @@
+/*
+ * The Rin Library – floating point module
+ *
+ * Copyright (C) 2015 Gediminas Jakutis
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; version 2.1
+ * of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include "rin/float.h"
+#include "rin/float_types.h"
+#include "float_private.h"
+
+/*
+ * TODO:
+ * · Doxygen-ize comments
+ * · Diagnostics
+ * · moar portability
+ * · ??
+ */
+
+/*
+ * signbit functions return the sign bit of a floating point number
+ * in the position where it is found on the raw float data itself.
+ * Set sign bit means it is negative
+ */
+uint32_t rin_signbitf(const float num)
+{
+ uint32_t ret;
+ ret = rin_float_to_uint(num);
+ return ret & 0x80000000u;
+}
+
+uint64_t rin_signbitd(const double num)
+{
+ uint64_t ret;
+ ret = rin_double_to_ulong(num);
+ return ret & 0x8000000000000000ull;
+}
+
+/*
+ * hexstring functions format a string of the hexidecimal representation
+ * of the raw floating point number data
+ *
+ * str has to point to enough memory to hold the said string
+ *
+ * mode hold modebits. Has to be either RIN_HEXSTRING_DEFAULT or any of
+ * the available modes ORed togther.
+ * Only one non-default mode is available at the moment.
+ */
+
+char *rin_float_to_hexstring(const float num, char *str, unsigned int mode)
+{
+ char buffer[16] = { '\0' };
+ uint32_t tmp;
+ size_t ccnt;
+
+ tmp = rin_float_to_uint(num);
+ ccnt = sprintf(buffer, "%x", tmp);
+
+ if (mode & RIN_HEXSTRING_NOPREFIX) {
+ memcpy(str, "00000000", 9);
+ memcpy(&str[8 - ccnt], buffer, ccnt);
+ } else {
+ memcpy(str, "0x00000000", 11);
+ memcpy(&str[10 - ccnt], buffer, ccnt);
+ }
+
+ return str;
+}
+
+char *rin_double_to_hexstring(const double num, char *str, unsigned int mode)
+{
+ char buffer[32] = { '\0' };
+ uint64_t tmp;
+ size_t ccnt;
+
+ tmp = rin_double_to_ulong(num);
+ ccnt = sprintf(buffer, "%lx", tmp);
+
+ if (mode & RIN_HEXSTRING_NOPREFIX) {
+ memcpy(str, "0000000000000000", 17);
+ memcpy(&str[16 - ccnt], buffer, ccnt);
+ } else {
+ memcpy(str, "0x0000000000000000", 19);
+ memcpy(&str[18 - ccnt], buffer, ccnt);
+ }
+
+ return str;
+}
+
+/*
+ * These comparison functions use Units In Last Place (ULPs) to check if the numbers
+ * are close enough to be considered equal, which addresses most shortcomings of
+ * epsilon-based comparison.
+ *
+ * TODO: Still not implemented optimally and can produce results worse than epsilon
+ * comparison in some situations.
+ */
+
+unsigned int rin_compare_float(const float a, const float b, uint32_t max_ulps)
+{
+ /* in case signs differ, "regular" comparison makes no sense */
+ if (rin_signbitf(a) != rin_signbitf(b)) {
+ /* unless it's a case of a signed zero, so check for that */
+ if (a == b) {
+ return 0;
+ } else {
+ return 1;
+ }
+ } else {
+ return ((uint32_t) abs(rin_float_to_int(a) - rin_float_to_int(b))) > max_ulps;
+ }
+}
+
+unsigned int rin_compare_vec2(const struct vec2 a, const struct vec2 b, uint32_t max_ulps)
+{
+ unsigned int ret;
+
+ ret = rin_compare_float(a.x, b.x, max_ulps);
+ ret += rin_compare_float(a.y, b.y, max_ulps);
+
+ return ret;
+}
+
+unsigned int rin_compare_vec3(const struct vec3 a, const struct vec3 b, uint32_t max_ulps)
+{
+ unsigned int ret;
+
+ ret = rin_compare_float(a.x, b.x, max_ulps);
+ ret += rin_compare_float(a.y, b.y, max_ulps);
+ ret += rin_compare_float(a.z, b.z, max_ulps);
+
+ return ret;
+}
+
+unsigned int rin_compare_vec4(const struct vec4 a, const struct vec4 b, uint32_t max_ulps)
+{
+ unsigned int ret;
+
+ ret = rin_compare_float(a.x, b.x, max_ulps);
+ ret += rin_compare_float(a.y, b.y, max_ulps);
+ ret += rin_compare_float(a.z, b.z, max_ulps);
+ ret += rin_compare_float(a.w, b.w, max_ulps);
+
+ return ret;
+}
+
+unsigned int rin_compare_double(const double a, const double b, uint64_t max_ulps)
+{
+ /* in case signs differ, "regular" comparison makes no sense */
+ if (rin_signbitd(a) != rin_signbitd(b)) {
+ /* unless it's a case of a signed zero, so check for that */
+ if (a == b) {
+ return 0;
+ } else {
+ return 1;
+ }
+ } else {
+ return ((uint64_t) labs(rin_double_to_long(a) - rin_double_to_long(b))) > max_ulps;
+ }
+}
+
+unsigned int rin_compare_vec2d(const struct vec2d a, const struct vec2d b, uint64_t max_ulps)
+{
+ unsigned int ret;
+
+ ret = rin_compare_double(a.x, b.x, max_ulps);
+ ret += rin_compare_double(a.y, b.y, max_ulps);
+
+ return ret;
+}
+
+unsigned int rin_compare_vec3d(const struct vec3d a, const struct vec3d b, uint64_t max_ulps)
+{
+ unsigned int ret;
+
+ ret = rin_compare_double(a.x, b.x, max_ulps);
+ ret += rin_compare_double(a.y, b.y, max_ulps);
+ ret += rin_compare_double(a.z, b.z, max_ulps);
+
+ return ret;
+}
+
+unsigned int rin_compare_vec4d(const struct vec4d a, const struct vec4d b, uint64_t max_ulps)
+{
+ unsigned int ret;
+
+ ret = rin_compare_double(a.x, b.x, max_ulps);
+ ret += rin_compare_double(a.y, b.y, max_ulps);
+ ret += rin_compare_double(a.z, b.z, max_ulps);
+ ret += rin_compare_double(a.w, b.w, max_ulps);
+
+ return ret;
+}
+
+/*
+ * These [float_type]_to_[integer_type] functions do type punning in a
+ * standards-compliant / without invoking undefined behavior, which
+ * happens in most of the [sadly] widely used methods to do this.
+ */
+
+uint32_t rin_float_to_uint(const float num)
+{
+ uint32_t ret;
+
+ memcpy(&ret, &num, sizeof(num));
+
+ return ret;
+}
+
+int32_t rin_float_to_int(const float num)
+{
+ int32_t ret;
+
+ memcpy(&ret, &num, sizeof(num));
+
+ return ret;
+}
+
+uint64_t rin_double_to_ulong(const double num)
+{
+ uint64_t ret;
+
+ memcpy(&ret, &num, sizeof(num));
+
+ return ret;
+}
+
+int64_t rin_double_to_long(const double num)
+{
+ int64_t ret;
+
+ memcpy(&ret, &num, sizeof(num));
+
+ return ret;
+}
diff --git a/src/float/float_private.h b/src/float/float_private.h
new file mode 100644
index 0000000..4eed70b
--- /dev/null
+++ b/src/float/float_private.h
@@ -0,0 +1,29 @@
+/*
+ * The Rin Library – floating point module
+ *
+ * Copyright (C) 2015 Gediminas Jakutis
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; version 2.1
+ * of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifndef LIBRIN_FLOAT_PRIVATE_INCLUDED
+#define LIBRIN_FLOAT_PRIVATE_INCLUDED
+
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+#include <stdio.h>
+
+#endif /* LIBRIN_FLOAT_PRIVATE_INCLUDED */