forked from osmocom/wireshark
![Dario Lombardo](/assets/img/avatar_default.png)
Skipping dissectors dir for now. Change-Id: I717b66bfbc7cc81b83f8c2cbc011fcad643796aa Reviewed-on: https://code.wireshark.org/review/25694 Petri-Dish: Dario Lombardo <lomato@gmail.com> Tested-by: Petri Dish Buildbot Reviewed-by: Anders Broman <a.broman58@gmail.com>
1520 lines
40 KiB
C
1520 lines
40 KiB
C
/* FLOATs as specified by ISO/IEEE Std. 11073-20601-2014
|
|
*
|
|
* Personal Health Devices Transcoding White Paper v1.5
|
|
* https://www.bluetooth.org/DocMan/handlers/DownloadDoc.ashx?doc_id=272346
|
|
*
|
|
* Wireshark - Network traffic analyzer
|
|
* By Gerald Combs <gerald@wireshark.org>
|
|
* Copyright 2001 Gerald Combs
|
|
*
|
|
* SPDX-License-Identifier: GPL-2.0-or-later
|
|
*/
|
|
|
|
#include "config.h"
|
|
|
|
#include <stdio.h>
|
|
#include <ftypes-int.h>
|
|
#include <math.h>
|
|
#include <errno.h>
|
|
#include <float.h>
|
|
|
|
#include "strutil.h"
|
|
|
|
#define DOUBLE_REPR_LENGTH 27
|
|
|
|
#define SFLOAT_VALUE_INFINITY_PLUS 0x07FE
|
|
#define SFLOAT_VALUE_NAN 0x07FF
|
|
#define SFLOAT_VALUE_NRES 0x0800
|
|
#define SFLOAT_VALUE_RFU 0x0801
|
|
#define SFLOAT_VALUE_INFINITY_MINUS 0x0802
|
|
|
|
#define FLOAT_VALUE_INFINITY_PLUS 0x007FFFFE
|
|
#define FLOAT_VALUE_NAN 0x007FFFFF
|
|
#define FLOAT_VALUE_NRES 0x00800000
|
|
#define FLOAT_VALUE_RFU 0x00800001
|
|
#define FLOAT_VALUE_INFINITY_MINUS 0x00800002
|
|
|
|
static void
|
|
sfloat_ieee_11073_fvalue_new(fvalue_t *fv)
|
|
{
|
|
fv->value.sfloat_ieee_11073 = 0x0000;
|
|
}
|
|
|
|
static gboolean
|
|
sfloat_ieee_11073_val_from_unparsed(fvalue_t *fv, const char *s, gboolean allow_partial_value _U_, gchar **err_msg _U_)
|
|
{
|
|
const char *i_char = s;
|
|
char c;
|
|
guint8 mantissa_sign = 0;
|
|
guint32 mantissa = 0;
|
|
gint8 exponent = 0;
|
|
gboolean fraction_mode = FALSE;
|
|
const guint16 mantissa_max = 0x07FF;
|
|
|
|
c = *i_char;
|
|
|
|
if (c== '\0')
|
|
return FALSE;
|
|
|
|
if (c == '.')
|
|
return FALSE;
|
|
|
|
if (c == '-' && s[1] == '.')
|
|
return FALSE;
|
|
|
|
if (c == '-' && (s[1] == 'I' || s[1] == 'i')) {
|
|
if (!g_ascii_strcasecmp(s, "-INFINITY")) {
|
|
fv->value.sfloat_ieee_11073 = SFLOAT_VALUE_INFINITY_MINUS;
|
|
return TRUE;
|
|
}
|
|
|
|
return FALSE;
|
|
} else if (c == 'R' || c == 'r') {
|
|
if (!g_ascii_strcasecmp(s, "RFU")) {
|
|
fv->value.sfloat_ieee_11073 = SFLOAT_VALUE_RFU;
|
|
return TRUE;
|
|
}
|
|
|
|
return FALSE;
|
|
} else if (c == 'N' || c == 'n') {
|
|
if (!g_ascii_strcasecmp(s, "NRes")) {
|
|
fv->value.sfloat_ieee_11073 = SFLOAT_VALUE_NRES;
|
|
return TRUE;
|
|
}
|
|
|
|
if (!g_ascii_strcasecmp(s, "NaN")) {
|
|
fv->value.sfloat_ieee_11073 = SFLOAT_VALUE_NAN;
|
|
return TRUE;
|
|
}
|
|
|
|
return FALSE;
|
|
} else if (c == '+') {
|
|
if (!g_ascii_strcasecmp(s, "+INFINITY")) {
|
|
fv->value.sfloat_ieee_11073 = SFLOAT_VALUE_INFINITY_PLUS;
|
|
return TRUE;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
if (c == '-') {
|
|
if (s[1] == '\0')
|
|
return FALSE;
|
|
|
|
mantissa_sign = 1;
|
|
i_char += 1;
|
|
}
|
|
|
|
while (*i_char == '0') {
|
|
i_char += 1;
|
|
}
|
|
|
|
c = *i_char;
|
|
|
|
do {
|
|
if (c == '0') {
|
|
if (mantissa * 10 > (guint32) mantissa_max + mantissa_sign) {
|
|
exponent += 1;
|
|
if (exponent > 7)
|
|
return FALSE;
|
|
} else {
|
|
mantissa *= 10;
|
|
}
|
|
} else if (c == '1') {
|
|
mantissa *= 10;
|
|
mantissa += 1;
|
|
} else if (c == '2') {
|
|
mantissa *= 10;
|
|
mantissa += 2;
|
|
} else if (c == '3') {
|
|
mantissa *= 10;
|
|
mantissa += 3;
|
|
} else if (c == '4') {
|
|
mantissa *= 10;
|
|
mantissa += 4;
|
|
} else if (c == '5') {
|
|
mantissa *= 10;
|
|
mantissa += 5;
|
|
} else if (c == '6') {
|
|
mantissa *= 10;
|
|
mantissa += 6;
|
|
} else if (c == '7') {
|
|
mantissa *= 10;
|
|
mantissa += 7;
|
|
} else if (c == '8') {
|
|
mantissa *= 10;
|
|
mantissa += 8;
|
|
} else if (c == '9') {
|
|
mantissa *= 10;
|
|
mantissa += 9;
|
|
} else if (c == '.') {
|
|
if (fraction_mode)
|
|
return FALSE;
|
|
fraction_mode = TRUE;
|
|
i_char += 1;
|
|
|
|
while (*i_char == '0') {
|
|
i_char += 1;
|
|
if (mantissa * 10 <= (guint32) mantissa_max + mantissa_sign) {
|
|
mantissa *= 10;
|
|
if (exponent > -8 - 4) /* -8 is min exponent; 4 is mantissa size */
|
|
exponent -= 1;
|
|
}
|
|
}
|
|
|
|
i_char -= 1;
|
|
} else if (c != '\0') {
|
|
/* NOTE: Maybe 5e-10, 5e3 notation should be also supported */
|
|
return FALSE;
|
|
}
|
|
|
|
if (mantissa > (guint32) mantissa_max + mantissa_sign)
|
|
return FALSE;
|
|
|
|
if (c != '.' && fraction_mode)
|
|
exponent -= 1;
|
|
|
|
i_char += 1;
|
|
} while ((c = *i_char));
|
|
|
|
if (mantissa_sign) {
|
|
mantissa = ~(mantissa - 1);
|
|
mantissa &= 0x0FFF;
|
|
}
|
|
|
|
/* Transform to normal form */
|
|
|
|
if (mantissa == 0)
|
|
exponent = 0;
|
|
|
|
while (mantissa > 0 && mantissa % 10 == 0 && exponent < 7) {
|
|
mantissa /= 10;
|
|
exponent += 1;
|
|
}
|
|
|
|
if (exponent < -8)
|
|
return FALSE;
|
|
|
|
fv->value.sfloat_ieee_11073 = ((exponent & 0x0F) << 12) | mantissa;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static void
|
|
sfloat_ieee_11073_val_to_repr(fvalue_t *fv, ftrepr_t rtype _U_, int field_display _U_, char *buf, unsigned int size)
|
|
{
|
|
gint8 exponent;
|
|
guint16 mantissa;
|
|
guint16 mantissa_sign;
|
|
guint32 offset = 0;
|
|
#define MANTISSA_STR_BUFFER_SIZE 5
|
|
gchar mantissa_str[MANTISSA_STR_BUFFER_SIZE];
|
|
guint8 mantissa_digits;
|
|
|
|
if (fv->value.sfloat_ieee_11073 >= 0x07FE && fv->value.sfloat_ieee_11073 <= 0x0802) {
|
|
switch (fv->value.sfloat_ieee_11073) {
|
|
case SFLOAT_VALUE_INFINITY_PLUS:
|
|
g_strlcpy(buf, "+INFINITY", size);
|
|
break;
|
|
case SFLOAT_VALUE_NAN:
|
|
g_strlcpy(buf, "NaN", size);
|
|
break;
|
|
case SFLOAT_VALUE_NRES:
|
|
g_strlcpy(buf, "NRes", size);
|
|
break;
|
|
case SFLOAT_VALUE_RFU:
|
|
g_strlcpy(buf, "RFU", size);
|
|
break;
|
|
case SFLOAT_VALUE_INFINITY_MINUS:
|
|
g_strlcpy(buf, "-INFINITY", size);
|
|
break;
|
|
}
|
|
return;
|
|
}
|
|
|
|
exponent = fv->value.sfloat_ieee_11073 >> 12;
|
|
if (exponent & 0x8)
|
|
exponent |= 0xF0; /* It is signed (4bits), so make it signed in gint8 */
|
|
mantissa = fv->value.sfloat_ieee_11073 & 0x07FF;
|
|
mantissa_sign = (fv->value.sfloat_ieee_11073 & 0x0800);
|
|
if (mantissa_sign)
|
|
mantissa = -((gint16)mantissa | 0xF800);
|
|
|
|
if (mantissa == 0) {
|
|
buf[0] = '0';
|
|
buf[1] = '\0';
|
|
|
|
return;
|
|
}
|
|
|
|
if (mantissa_sign) {
|
|
buf[0] = '-';
|
|
offset += 1;
|
|
}
|
|
|
|
mantissa_digits = g_snprintf(mantissa_str, MANTISSA_STR_BUFFER_SIZE, "%u", mantissa);
|
|
|
|
if (exponent == 0) {
|
|
memcpy(buf + offset, mantissa_str, mantissa_digits);
|
|
offset += mantissa_digits;
|
|
} else if (exponent > 0) {
|
|
memcpy(buf + offset, mantissa_str, mantissa_digits);
|
|
offset += mantissa_digits;
|
|
|
|
memset(buf + offset, '0', exponent);
|
|
offset += exponent;
|
|
} else /* if (exponent < 0)*/ {
|
|
if (-exponent < mantissa_digits) {
|
|
memcpy(buf + offset, mantissa_str, mantissa_digits + exponent);
|
|
offset += mantissa_digits + exponent;
|
|
|
|
buf[offset] = '.';
|
|
offset += 1;
|
|
|
|
memcpy(buf + offset, mantissa_str + mantissa_digits + exponent, -exponent);
|
|
offset += -exponent;
|
|
} else {
|
|
buf[offset] = '0';
|
|
offset += 1;
|
|
|
|
buf[offset] = '.';
|
|
offset += 1;
|
|
|
|
if (-exponent - mantissa_digits > 0) {
|
|
memset(buf + offset, '0', -exponent - mantissa_digits);
|
|
offset += -exponent - mantissa_digits;
|
|
}
|
|
|
|
memcpy(buf + offset, mantissa_str, mantissa_digits);
|
|
offset += mantissa_digits;
|
|
}
|
|
}
|
|
|
|
buf[offset] = '\0';
|
|
}
|
|
|
|
static int
|
|
sfloat_ieee_11073_val_repr_len(fvalue_t *fv _U_, ftrepr_t rtype _U_, int field_display _U_)
|
|
{
|
|
/* Predefinied: +INFINITY, -INFINITY, RFU, NRes, NaN */
|
|
/* Longest Signed Float Number: -0.00002048 (11 characters without NULL) */
|
|
/* Longest Signed Float Number -0.00000001 */
|
|
/* Longest Signed Nonfloat Number: -20480000000 (12 characters without NULL) */
|
|
/* NOTE: Possible memory optimization: compute length, but watch out for speed */
|
|
return 13;
|
|
}
|
|
|
|
static void
|
|
sfloat_ieee_11073_value_set(fvalue_t *fv, guint32 value)
|
|
{
|
|
fv->value.sfloat_ieee_11073 = (guint16) value;
|
|
}
|
|
|
|
static guint32
|
|
sfloat_ieee_11073_value_get(fvalue_t *fv)
|
|
{
|
|
return (guint32) fv->value.sfloat_ieee_11073;
|
|
}
|
|
|
|
static guint16 sfloat_to_normal_form(guint16 value)
|
|
{
|
|
gint8 exponent;
|
|
guint16 mantissa;
|
|
guint8 mantissa_sign;
|
|
|
|
if (value >= 0x07FE && value <= 0x0802) /* Save special values */
|
|
return value;
|
|
|
|
mantissa = value & 0x07FF;
|
|
if (value & 0x0800) {
|
|
mantissa = -((gint16)mantissa | 0xF800);
|
|
mantissa_sign = 1;
|
|
} else {
|
|
mantissa_sign = 0;
|
|
}
|
|
|
|
exponent = value >> 12;
|
|
|
|
if (exponent & 0x08) {
|
|
exponent |= 0xF0;
|
|
}
|
|
|
|
while ((!(mantissa % 10)) && mantissa != 0) {
|
|
mantissa /= 10;
|
|
|
|
if (exponent == 7)
|
|
break;
|
|
|
|
exponent += 1;
|
|
}
|
|
|
|
return ((((exponent & 0x80) ? 0x8 : 0x0 ) | (exponent & 0x7)) << 12) | (mantissa_sign << 11) | mantissa;
|
|
}
|
|
|
|
static gboolean
|
|
sfloat_ieee_11073_cmp_eq(const fvalue_t *a, const fvalue_t *b)
|
|
{
|
|
return sfloat_to_normal_form(a->value.sfloat_ieee_11073) == sfloat_to_normal_form(b->value.sfloat_ieee_11073);
|
|
}
|
|
|
|
static gboolean
|
|
sfloat_ieee_11073_cmp_ne(const fvalue_t *a, const fvalue_t *b)
|
|
{
|
|
return sfloat_to_normal_form(a->value.sfloat_ieee_11073) != sfloat_to_normal_form(b->value.sfloat_ieee_11073);
|
|
}
|
|
|
|
static gboolean
|
|
sfloat_ieee_11073_cmp_gt(const fvalue_t *a, const fvalue_t *b)
|
|
{
|
|
guint16 a_norm;
|
|
guint16 b_norm;
|
|
gint16 a_norm_mantissa;
|
|
gint16 b_norm_mantissa;
|
|
gint8 a_norm_exponent;
|
|
gint8 b_norm_exponent;
|
|
|
|
a_norm = sfloat_to_normal_form(a->value.sfloat_ieee_11073);
|
|
b_norm = sfloat_to_normal_form(b->value.sfloat_ieee_11073);
|
|
|
|
if (a_norm == b_norm)
|
|
return FALSE;
|
|
|
|
switch (a_norm) {
|
|
case SFLOAT_VALUE_NAN:
|
|
case SFLOAT_VALUE_NRES:
|
|
case SFLOAT_VALUE_RFU:
|
|
case SFLOAT_VALUE_INFINITY_MINUS:
|
|
return FALSE;
|
|
case SFLOAT_VALUE_INFINITY_PLUS:
|
|
switch (b_norm) {
|
|
case SFLOAT_VALUE_NAN:
|
|
case SFLOAT_VALUE_NRES:
|
|
case SFLOAT_VALUE_RFU:
|
|
case SFLOAT_VALUE_INFINITY_PLUS: /* Dead, informative case */
|
|
return FALSE;
|
|
case SFLOAT_VALUE_INFINITY_MINUS:
|
|
default:
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
a_norm_mantissa = a_norm & 0x0FFF;
|
|
b_norm_mantissa = b_norm & 0x0FFF;
|
|
if (a_norm & 0x0800)
|
|
a_norm_mantissa |= 0xF000;
|
|
|
|
if (b_norm & 0x0800)
|
|
b_norm_mantissa |= 0xF000;
|
|
|
|
a_norm_exponent = a_norm >> 12;
|
|
b_norm_exponent = b_norm >> 12;
|
|
|
|
if (a_norm_exponent & 0x08) {
|
|
a_norm_exponent |= 0xF0;
|
|
}
|
|
|
|
if (b_norm_exponent & 0x08) {
|
|
b_norm_exponent |= 0xF0;
|
|
}
|
|
|
|
if (a_norm_mantissa == b_norm_mantissa && a_norm_exponent > b_norm_exponent)
|
|
return TRUE;
|
|
|
|
if (a_norm_exponent == b_norm_exponent && a_norm_mantissa > b_norm_mantissa)
|
|
return TRUE;
|
|
|
|
if (a_norm_exponent < b_norm_exponent) {
|
|
guint8 exponent_difference;
|
|
|
|
exponent_difference = b_norm_exponent - a_norm_exponent;
|
|
|
|
if (exponent_difference >= 4)
|
|
return FALSE;
|
|
|
|
while (exponent_difference--) {
|
|
b_norm_mantissa *= 10;
|
|
}
|
|
} else {
|
|
guint8 exponent_difference;
|
|
|
|
exponent_difference = a_norm_exponent - b_norm_exponent;
|
|
|
|
if (exponent_difference >= 4)
|
|
return TRUE;
|
|
|
|
while (exponent_difference--) {
|
|
a_norm_mantissa *= 10;
|
|
}
|
|
}
|
|
|
|
if (a_norm_mantissa > b_norm_mantissa)
|
|
return TRUE;
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
static gboolean
|
|
sfloat_ieee_11073_cmp_ge(const fvalue_t *a, const fvalue_t *b)
|
|
{
|
|
guint16 a_norm;
|
|
guint16 b_norm;
|
|
gint16 a_norm_mantissa;
|
|
gint16 b_norm_mantissa;
|
|
gint8 a_norm_exponent;
|
|
gint8 b_norm_exponent;
|
|
|
|
a_norm = sfloat_to_normal_form(a->value.sfloat_ieee_11073);
|
|
b_norm = sfloat_to_normal_form(b->value.sfloat_ieee_11073);
|
|
|
|
if (a_norm == b_norm)
|
|
return TRUE;
|
|
|
|
switch (a_norm) {
|
|
case SFLOAT_VALUE_NAN:
|
|
case SFLOAT_VALUE_NRES:
|
|
case SFLOAT_VALUE_RFU:
|
|
case SFLOAT_VALUE_INFINITY_MINUS:
|
|
return FALSE;
|
|
case SFLOAT_VALUE_INFINITY_PLUS:
|
|
switch (b_norm) {
|
|
case SFLOAT_VALUE_NAN:
|
|
case SFLOAT_VALUE_NRES:
|
|
case SFLOAT_VALUE_RFU:
|
|
case SFLOAT_VALUE_INFINITY_PLUS: /* Dead, informative case */
|
|
return FALSE;
|
|
case SFLOAT_VALUE_INFINITY_MINUS:
|
|
default:
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
a_norm_mantissa = a_norm & 0x0FFF;
|
|
b_norm_mantissa = b_norm & 0x0FFF;
|
|
if (a_norm & 0x0800)
|
|
a_norm_mantissa |= 0xF000;
|
|
|
|
if (b_norm & 0x0800)
|
|
b_norm_mantissa |= 0xF000;
|
|
|
|
a_norm_exponent = a_norm >> 12;
|
|
b_norm_exponent = b_norm >> 12;
|
|
|
|
if (a_norm_exponent & 0x08) {
|
|
a_norm_exponent |= 0xF0;
|
|
}
|
|
|
|
if (b_norm_exponent & 0x08) {
|
|
b_norm_exponent |= 0xF0;
|
|
}
|
|
|
|
if (a_norm_mantissa == b_norm_mantissa && a_norm_exponent >= b_norm_exponent)
|
|
return TRUE;
|
|
|
|
if (a_norm_exponent == b_norm_exponent && a_norm_mantissa >= b_norm_mantissa)
|
|
return TRUE;
|
|
|
|
if (a_norm_exponent < b_norm_exponent) {
|
|
guint8 exponent_difference;
|
|
|
|
exponent_difference = b_norm_exponent - a_norm_exponent;
|
|
|
|
if (exponent_difference >= 4)
|
|
return FALSE;
|
|
|
|
while (exponent_difference--) {
|
|
b_norm_mantissa *= 10;
|
|
}
|
|
} else {
|
|
guint8 exponent_difference;
|
|
|
|
exponent_difference = a_norm_exponent - b_norm_exponent;
|
|
|
|
if (exponent_difference >= 4)
|
|
return TRUE;
|
|
|
|
while (exponent_difference--) {
|
|
a_norm_mantissa *= 10;
|
|
}
|
|
}
|
|
|
|
if (a_norm_mantissa > b_norm_mantissa)
|
|
return TRUE;
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
static gboolean
|
|
sfloat_ieee_11073_cmp_lt(const fvalue_t *a, const fvalue_t *b)
|
|
{
|
|
guint16 a_norm;
|
|
guint16 b_norm;
|
|
gint16 a_norm_mantissa;
|
|
gint16 b_norm_mantissa;
|
|
gint8 a_norm_exponent;
|
|
gint8 b_norm_exponent;
|
|
|
|
a_norm = sfloat_to_normal_form(a->value.sfloat_ieee_11073);
|
|
b_norm = sfloat_to_normal_form(b->value.sfloat_ieee_11073);
|
|
|
|
if (a_norm == b_norm)
|
|
return FALSE;
|
|
|
|
switch (a_norm) {
|
|
case SFLOAT_VALUE_NAN:
|
|
case SFLOAT_VALUE_NRES:
|
|
case SFLOAT_VALUE_RFU:
|
|
case SFLOAT_VALUE_INFINITY_PLUS:
|
|
return FALSE;
|
|
case SFLOAT_VALUE_INFINITY_MINUS:
|
|
switch (b_norm) {
|
|
case SFLOAT_VALUE_NAN:
|
|
case SFLOAT_VALUE_NRES:
|
|
case SFLOAT_VALUE_RFU:
|
|
case SFLOAT_VALUE_INFINITY_MINUS: /* Dead, informative case */
|
|
return FALSE;
|
|
case SFLOAT_VALUE_INFINITY_PLUS:
|
|
default:
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
a_norm_mantissa = a_norm & 0x0FFF;
|
|
b_norm_mantissa = b_norm & 0x0FFF;
|
|
if (a_norm & 0x0800)
|
|
a_norm_mantissa |= 0xFFFFF000;
|
|
|
|
if (b_norm & 0x0800)
|
|
b_norm_mantissa |= 0xFFFFF000;
|
|
|
|
a_norm_exponent = a_norm >> 12;
|
|
b_norm_exponent = b_norm >> 12;
|
|
|
|
if (a_norm_exponent & 0x08) {
|
|
a_norm_exponent |= 0xF0;
|
|
}
|
|
|
|
if (b_norm_exponent & 0x08) {
|
|
b_norm_exponent |= 0xF0;
|
|
}
|
|
|
|
if (a_norm_mantissa == b_norm_mantissa && a_norm_exponent < b_norm_exponent)
|
|
return TRUE;
|
|
|
|
if (a_norm_exponent == b_norm_exponent && a_norm_mantissa < b_norm_mantissa)
|
|
return TRUE;
|
|
|
|
if (a_norm_exponent < b_norm_exponent) {
|
|
guint8 exponent_difference;
|
|
|
|
exponent_difference = b_norm_exponent - a_norm_exponent;
|
|
|
|
if (exponent_difference >= 4)
|
|
return TRUE;
|
|
|
|
while (exponent_difference--) {
|
|
b_norm_mantissa *= 10;
|
|
}
|
|
} else {
|
|
guint8 exponent_difference;
|
|
|
|
exponent_difference = a_norm_exponent - b_norm_exponent;
|
|
|
|
if (exponent_difference >= 4)
|
|
return FALSE;
|
|
|
|
while (exponent_difference--) {
|
|
a_norm_mantissa *= 10;
|
|
}
|
|
}
|
|
|
|
if (a_norm_mantissa < b_norm_mantissa)
|
|
return TRUE;
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
static gboolean
|
|
sfloat_ieee_11073_cmp_le(const fvalue_t *a, const fvalue_t *b)
|
|
{
|
|
guint16 a_norm;
|
|
guint16 b_norm;
|
|
gint16 a_norm_mantissa;
|
|
gint16 b_norm_mantissa;
|
|
gint8 a_norm_exponent;
|
|
gint8 b_norm_exponent;
|
|
|
|
a_norm = sfloat_to_normal_form(a->value.sfloat_ieee_11073);
|
|
b_norm = sfloat_to_normal_form(b->value.sfloat_ieee_11073);
|
|
|
|
if (a_norm == b_norm)
|
|
return TRUE;
|
|
|
|
switch (a_norm) {
|
|
case SFLOAT_VALUE_NAN:
|
|
case SFLOAT_VALUE_NRES:
|
|
case SFLOAT_VALUE_RFU:
|
|
case SFLOAT_VALUE_INFINITY_PLUS:
|
|
return FALSE;
|
|
case SFLOAT_VALUE_INFINITY_MINUS:
|
|
switch (b_norm) {
|
|
case SFLOAT_VALUE_NAN:
|
|
case SFLOAT_VALUE_NRES:
|
|
case SFLOAT_VALUE_RFU:
|
|
case SFLOAT_VALUE_INFINITY_MINUS: /* Dead, informative case */
|
|
return FALSE;
|
|
case SFLOAT_VALUE_INFINITY_PLUS:
|
|
default:
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
a_norm_mantissa = a_norm & 0x0FFF;
|
|
b_norm_mantissa = b_norm & 0x0FFF;
|
|
if (a_norm & 0x0800)
|
|
a_norm_mantissa |= 0xF000;
|
|
|
|
if (b_norm & 0x0800)
|
|
b_norm_mantissa |= 0xF000;
|
|
|
|
a_norm_exponent = a_norm >> 12;
|
|
b_norm_exponent = b_norm >> 12;
|
|
|
|
if (a_norm_exponent & 0x08) {
|
|
a_norm_exponent |= 0xF0;
|
|
}
|
|
|
|
if (b_norm_exponent & 0x08) {
|
|
b_norm_exponent |= 0xF0;
|
|
}
|
|
|
|
if (a_norm_mantissa == b_norm_mantissa && a_norm_exponent <= b_norm_exponent)
|
|
return TRUE;
|
|
|
|
if (a_norm_exponent == b_norm_exponent && a_norm_mantissa <= b_norm_mantissa)
|
|
return TRUE;
|
|
|
|
if (a_norm_exponent < b_norm_exponent) {
|
|
guint8 exponent_difference;
|
|
|
|
exponent_difference = b_norm_exponent - a_norm_exponent;
|
|
|
|
if (exponent_difference >= 4)
|
|
return TRUE;
|
|
|
|
while (exponent_difference--) {
|
|
b_norm_mantissa *= 10;
|
|
}
|
|
} else {
|
|
guint8 exponent_difference;
|
|
|
|
exponent_difference = a_norm_exponent - b_norm_exponent;
|
|
|
|
if (exponent_difference >= 4)
|
|
return FALSE;
|
|
|
|
while (exponent_difference--) {
|
|
a_norm_mantissa *= 10;
|
|
}
|
|
}
|
|
|
|
if (a_norm_mantissa < b_norm_mantissa)
|
|
return TRUE;
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
static gboolean
|
|
sfloat_ieee_11073_cmp_bitwise_and(const fvalue_t *a, const fvalue_t *b)
|
|
{
|
|
return ((a->value.uinteger & b->value.uinteger) != 0);
|
|
}
|
|
|
|
/*============================================================================*/
|
|
|
|
static void
|
|
float_ieee_11073_fvalue_new(fvalue_t *fv)
|
|
{
|
|
fv->value.float_ieee_11073 = 0x0000;
|
|
}
|
|
|
|
static gboolean
|
|
float_ieee_11073_val_from_unparsed(fvalue_t *fv, const char *s, gboolean allow_partial_value _U_, gchar **err_msg _U_)
|
|
{
|
|
const char *i_char = s;
|
|
char c;
|
|
guint8 mantissa_sign = 0;
|
|
guint32 mantissa = 0;
|
|
gint16 exponent = 0;
|
|
gboolean fraction_mode = FALSE;
|
|
const guint32 mantissa_max = 0x007FFFFF;
|
|
|
|
c = *i_char;
|
|
|
|
if (c== '\0')
|
|
return FALSE;
|
|
|
|
if (c == '.')
|
|
return FALSE;
|
|
|
|
if (c == '-' && s[1] == '.')
|
|
return FALSE;
|
|
|
|
if (c == '-' && (s[1] == 'I' || s[1] == 'i')) {
|
|
if (!g_ascii_strcasecmp(s, "-INFINITY")) {
|
|
fv->value.float_ieee_11073 = FLOAT_VALUE_INFINITY_MINUS;
|
|
return TRUE;
|
|
}
|
|
|
|
return FALSE;
|
|
} else if (c == 'R' || c == 'r') {
|
|
if (!g_ascii_strcasecmp(s, "RFU")) {
|
|
fv->value.float_ieee_11073 = FLOAT_VALUE_RFU;
|
|
return TRUE;
|
|
}
|
|
|
|
return FALSE;
|
|
} else if (c == 'N' || c == 'n') {
|
|
if (!g_ascii_strcasecmp(s, "NRes")) {
|
|
fv->value.float_ieee_11073 = FLOAT_VALUE_NRES;
|
|
return TRUE;
|
|
}
|
|
|
|
if (!g_ascii_strcasecmp(s, "NaN")) {
|
|
fv->value.float_ieee_11073 = FLOAT_VALUE_NAN;
|
|
return TRUE;
|
|
}
|
|
|
|
return FALSE;
|
|
} else if (c == '+') {
|
|
if (!g_ascii_strcasecmp(s, "+INFINITY")) {
|
|
fv->value.float_ieee_11073 = FLOAT_VALUE_INFINITY_PLUS;
|
|
return TRUE;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
if (c == '-') {
|
|
if (s[1] == '\0')
|
|
return FALSE;
|
|
|
|
mantissa_sign = 1;
|
|
i_char += 1;
|
|
}
|
|
|
|
while (*i_char == '0') {
|
|
i_char += 1;
|
|
}
|
|
|
|
c = *i_char;
|
|
|
|
do {
|
|
if (c == '0') {
|
|
if (mantissa * 10 > mantissa_sign + mantissa_max) {
|
|
exponent += 1;
|
|
if (exponent <= 127)
|
|
return FALSE;
|
|
} else {
|
|
mantissa *= 10;
|
|
}
|
|
} else if (c == '1') {
|
|
mantissa *= 10;
|
|
mantissa += 1;
|
|
} else if (c == '2') {
|
|
mantissa *= 10;
|
|
mantissa += 2;
|
|
} else if (c == '3') {
|
|
mantissa *= 10;
|
|
mantissa += 3;
|
|
} else if (c == '4') {
|
|
mantissa *= 10;
|
|
mantissa += 4;
|
|
} else if (c == '5') {
|
|
mantissa *= 10;
|
|
mantissa += 5;
|
|
} else if (c == '6') {
|
|
mantissa *= 10;
|
|
mantissa += 6;
|
|
} else if (c == '7') {
|
|
mantissa *= 10;
|
|
mantissa += 7;
|
|
} else if (c == '8') {
|
|
mantissa *= 10;
|
|
mantissa += 8;
|
|
} else if (c == '9') {
|
|
mantissa *= 10;
|
|
mantissa += 9;
|
|
} else if (c == '.') {
|
|
if (fraction_mode)
|
|
return FALSE;
|
|
fraction_mode = TRUE;
|
|
i_char += 1;
|
|
|
|
while (*i_char == '0') {
|
|
i_char += 1;
|
|
if (mantissa * 10 <= mantissa_max + mantissa_sign) {
|
|
mantissa *= 10;
|
|
if (exponent > -128 - 7) /* -8 is min exponent; 4 is mantissa size */
|
|
exponent -= 1;
|
|
}
|
|
}
|
|
|
|
i_char -= 1;
|
|
} else if (c != '\0') {
|
|
/* NOTE: Maybe 5e-10, 5e3 notation should be also supported */
|
|
return FALSE;
|
|
}
|
|
|
|
if (mantissa > mantissa_max + mantissa_sign)
|
|
return FALSE;
|
|
|
|
if (c != '.' && fraction_mode)
|
|
exponent -= 1;
|
|
|
|
i_char += 1;
|
|
} while ((c = *i_char));
|
|
|
|
if (mantissa_sign) {
|
|
mantissa = ~(mantissa - 1);
|
|
mantissa &= 0x00FFFFFF;
|
|
}
|
|
|
|
/* Transform to normal form */
|
|
|
|
if (mantissa == 0)
|
|
exponent = 0;
|
|
|
|
while (mantissa > 0 && mantissa % 10 == 0 && exponent < 127) {
|
|
mantissa /= 10;
|
|
exponent += 1;
|
|
}
|
|
|
|
if (exponent < -128)
|
|
return FALSE;
|
|
|
|
fv->value.float_ieee_11073 = ((exponent & 0xFF) << 24) | mantissa;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static void
|
|
float_ieee_11073_val_to_repr(fvalue_t *fv, ftrepr_t rtype _U_, int field_display _U_, char *buf, unsigned int size)
|
|
{
|
|
gint8 exponent;
|
|
guint32 mantissa;
|
|
guint32 mantissa_sign;
|
|
guint32 offset = 0;
|
|
gchar mantissa_str[8];
|
|
guint8 mantissa_digits;
|
|
|
|
if (fv->value.float_ieee_11073 >= 0x007FFFFE && fv->value.float_ieee_11073 <= 0x00800002) {
|
|
switch (fv->value.float_ieee_11073) {
|
|
case FLOAT_VALUE_INFINITY_PLUS:
|
|
g_strlcpy(buf, "+INFINITY", size);
|
|
break;
|
|
case FLOAT_VALUE_NAN:
|
|
g_strlcpy(buf, "NaN", size);
|
|
break;
|
|
case FLOAT_VALUE_NRES:
|
|
g_strlcpy(buf, "NRes", size);
|
|
break;
|
|
case FLOAT_VALUE_RFU:
|
|
g_strlcpy(buf, "RFU", size);
|
|
break;
|
|
case FLOAT_VALUE_INFINITY_MINUS:
|
|
g_strlcpy(buf, "-INFINITY", size);
|
|
break;
|
|
}
|
|
}
|
|
|
|
exponent = fv->value.float_ieee_11073 >> 24;
|
|
|
|
mantissa = fv->value.float_ieee_11073 & 0x007FFFFF;
|
|
mantissa_sign = (fv->value.float_ieee_11073 & 0x00800000);
|
|
if (mantissa_sign)
|
|
mantissa = (guint32)(-((gint32)(mantissa | 0xFF000000)));
|
|
|
|
if (mantissa == 0) {
|
|
buf[0] = '0';
|
|
buf[1] = '\0';
|
|
|
|
return;
|
|
}
|
|
|
|
if (mantissa_sign) {
|
|
buf[0] = '-';
|
|
offset += 1;
|
|
}
|
|
|
|
mantissa_digits = g_snprintf(mantissa_str, size, "%u", mantissa);
|
|
|
|
if (exponent == 0) {
|
|
memcpy(buf + offset, mantissa_str, mantissa_digits);
|
|
offset += mantissa_digits;
|
|
} else if (exponent > 0) {
|
|
memcpy(buf + offset, mantissa_str, mantissa_digits);
|
|
offset += mantissa_digits;
|
|
|
|
memset(buf + offset, '0', exponent);
|
|
offset += exponent;
|
|
} else /* if (exponent < 0)*/ {
|
|
if (-exponent < mantissa_digits) {
|
|
memcpy(buf + offset, mantissa_str, mantissa_digits + exponent);
|
|
offset += mantissa_digits + exponent;
|
|
|
|
buf[offset] = '.';
|
|
offset += 1;
|
|
|
|
memcpy(buf + offset, mantissa_str + mantissa_digits + exponent, -exponent);
|
|
offset += -exponent;
|
|
} else {
|
|
buf[offset] = '0';
|
|
offset += 1;
|
|
|
|
buf[offset] = '.';
|
|
offset += 1;
|
|
|
|
if (-exponent - mantissa_digits > 0) {
|
|
memset(buf + offset, '0', -exponent - mantissa_digits);
|
|
offset += -exponent - mantissa_digits;
|
|
}
|
|
|
|
memcpy(buf + offset, mantissa_str, mantissa_digits);
|
|
offset += mantissa_digits;
|
|
}
|
|
}
|
|
|
|
buf[offset] = '\0';
|
|
}
|
|
|
|
static int
|
|
float_ieee_11073_val_repr_len(fvalue_t *fv _U_, ftrepr_t rtype _U_, int field_display _U_)
|
|
{
|
|
/* Predefinied: +INFINITY, -INFINITY, RFU, NRes, NaN */
|
|
/* Longest Signed Nonfloat Number: -8388608*(10^-128) (1 character for sign, 7 for mantisa digits, 127 zeros, 1 character for NULL) */
|
|
/* NOTE: Possible memory optimization: compute length, but watch out for speed */
|
|
return 136;
|
|
}
|
|
|
|
static void
|
|
float_ieee_11073_value_set(fvalue_t *fv, guint32 value)
|
|
{
|
|
fv->value.float_ieee_11073 = value;
|
|
}
|
|
|
|
static guint32
|
|
float_ieee_11073_value_get(fvalue_t *fv)
|
|
{
|
|
return fv->value.float_ieee_11073;
|
|
}
|
|
|
|
static guint32 float_to_normal_form(guint32 value)
|
|
{
|
|
gint8 exponent;
|
|
guint16 mantissa;
|
|
guint8 mantissa_sign;
|
|
|
|
if (value >= 0x007FFFFE && value <= 0x00800002) /* Save special values */
|
|
return value;
|
|
|
|
mantissa = value & 0x907FFFFF;
|
|
if (value & 0x00800000) {
|
|
mantissa = (guint32)(-((gint32)(mantissa | 0xFF000000)));
|
|
mantissa_sign = 1;
|
|
} else {
|
|
mantissa_sign = 0;
|
|
}
|
|
|
|
exponent = value >> 24;
|
|
|
|
while ((!(mantissa % 10)) && mantissa != 0) {
|
|
mantissa /= 10;
|
|
|
|
if (exponent == 127)
|
|
break;
|
|
|
|
exponent += 1;
|
|
}
|
|
|
|
return (exponent << 24) | (mantissa_sign << 23) | mantissa;
|
|
}
|
|
|
|
static gboolean
|
|
float_ieee_11073_cmp_eq(const fvalue_t *a, const fvalue_t *b)
|
|
{
|
|
return float_to_normal_form(a->value.float_ieee_11073) == float_to_normal_form(b->value.float_ieee_11073);
|
|
}
|
|
|
|
static gboolean
|
|
float_ieee_11073_cmp_ne(const fvalue_t *a, const fvalue_t *b)
|
|
{
|
|
return float_to_normal_form(a->value.float_ieee_11073) != float_to_normal_form(b->value.float_ieee_11073);
|
|
}
|
|
|
|
static gboolean
|
|
float_ieee_11073_cmp_gt(const fvalue_t *a, const fvalue_t *b)
|
|
{
|
|
guint32 a_norm;
|
|
guint32 b_norm;
|
|
gint32 a_norm_mantissa;
|
|
gint32 b_norm_mantissa;
|
|
gint8 a_norm_exponent;
|
|
gint8 b_norm_exponent;
|
|
|
|
a_norm = float_to_normal_form(a->value.float_ieee_11073);
|
|
b_norm = float_to_normal_form(b->value.float_ieee_11073);
|
|
|
|
if (a_norm == b_norm)
|
|
return FALSE;
|
|
|
|
switch (a_norm) {
|
|
case FLOAT_VALUE_NAN:
|
|
case FLOAT_VALUE_NRES:
|
|
case FLOAT_VALUE_RFU:
|
|
case FLOAT_VALUE_INFINITY_MINUS:
|
|
return FALSE;
|
|
case FLOAT_VALUE_INFINITY_PLUS:
|
|
switch (b_norm) {
|
|
case FLOAT_VALUE_NAN:
|
|
case FLOAT_VALUE_NRES:
|
|
case FLOAT_VALUE_RFU:
|
|
case FLOAT_VALUE_INFINITY_PLUS: /* Dead, informative case */
|
|
return FALSE;
|
|
case FLOAT_VALUE_INFINITY_MINUS:
|
|
default:
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
a_norm_mantissa = a_norm & 0x00FFFFFF;
|
|
b_norm_mantissa = b_norm & 0x00FFFFFF;
|
|
if (a_norm & 0x00800000)
|
|
a_norm_mantissa |= 0xFF000000;
|
|
|
|
if (b_norm & 0x00800000)
|
|
b_norm_mantissa |= 0xFF000000;
|
|
|
|
a_norm_exponent = a_norm >> 24;
|
|
b_norm_exponent = b_norm >> 24;
|
|
|
|
if (a_norm_mantissa == b_norm_mantissa && a_norm_exponent > b_norm_exponent)
|
|
return TRUE;
|
|
|
|
if (a_norm_exponent == b_norm_exponent && a_norm_mantissa > b_norm_mantissa)
|
|
return TRUE;
|
|
|
|
if (a_norm_exponent < b_norm_exponent) {
|
|
guint8 exponent_difference;
|
|
|
|
exponent_difference = b_norm_exponent - a_norm_exponent;
|
|
|
|
if (exponent_difference >= 7)
|
|
return FALSE;
|
|
|
|
while (exponent_difference--) {
|
|
b_norm_mantissa *= 10;
|
|
}
|
|
} else {
|
|
guint8 exponent_difference;
|
|
|
|
exponent_difference = a_norm_exponent - b_norm_exponent;
|
|
|
|
if (exponent_difference >= 7)
|
|
return TRUE;
|
|
|
|
while (exponent_difference--) {
|
|
a_norm_mantissa *= 10;
|
|
}
|
|
}
|
|
|
|
if (a_norm_mantissa > b_norm_mantissa)
|
|
return TRUE;
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
static gboolean
|
|
float_ieee_11073_cmp_ge(const fvalue_t *a, const fvalue_t *b)
|
|
{
|
|
guint32 a_norm;
|
|
guint32 b_norm;
|
|
gint32 a_norm_mantissa;
|
|
gint32 b_norm_mantissa;
|
|
gint8 a_norm_exponent;
|
|
gint8 b_norm_exponent;
|
|
|
|
a_norm = float_to_normal_form(a->value.float_ieee_11073);
|
|
b_norm = float_to_normal_form(b->value.float_ieee_11073);
|
|
|
|
if (a_norm == b_norm)
|
|
return TRUE;
|
|
|
|
switch (a_norm) {
|
|
case FLOAT_VALUE_NAN:
|
|
case FLOAT_VALUE_NRES:
|
|
case FLOAT_VALUE_RFU:
|
|
case FLOAT_VALUE_INFINITY_MINUS:
|
|
return FALSE;
|
|
case FLOAT_VALUE_INFINITY_PLUS:
|
|
switch (b_norm) {
|
|
case FLOAT_VALUE_NAN:
|
|
case FLOAT_VALUE_NRES:
|
|
case FLOAT_VALUE_RFU:
|
|
case FLOAT_VALUE_INFINITY_PLUS: /* Dead, informative case */
|
|
return FALSE;
|
|
case FLOAT_VALUE_INFINITY_MINUS:
|
|
default:
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
a_norm_mantissa = a_norm & 0x00FFFFFF;
|
|
b_norm_mantissa = b_norm & 0x00FFFFFF;
|
|
if (a_norm & 0x00800000)
|
|
a_norm_mantissa |= 0xFF000000;
|
|
|
|
if (b_norm & 0x00800000)
|
|
b_norm_mantissa |= 0xFF000000;
|
|
|
|
a_norm_exponent = a_norm >> 24;
|
|
b_norm_exponent = b_norm >> 24;
|
|
|
|
if (a_norm_mantissa == b_norm_mantissa && a_norm_exponent >= b_norm_exponent)
|
|
return TRUE;
|
|
|
|
if (a_norm_exponent == b_norm_exponent && a_norm_mantissa >= b_norm_mantissa)
|
|
return TRUE;
|
|
|
|
if (a_norm_exponent < b_norm_exponent) {
|
|
guint8 exponent_difference;
|
|
|
|
exponent_difference = b_norm_exponent - a_norm_exponent;
|
|
|
|
if (exponent_difference >= 7)
|
|
return FALSE;
|
|
|
|
while (exponent_difference--) {
|
|
b_norm_mantissa *= 10;
|
|
}
|
|
} else {
|
|
guint8 exponent_difference;
|
|
|
|
exponent_difference = a_norm_exponent - b_norm_exponent;
|
|
|
|
if (exponent_difference >= 7)
|
|
return TRUE;
|
|
|
|
while (exponent_difference--) {
|
|
a_norm_mantissa *= 10;
|
|
}
|
|
}
|
|
|
|
if (a_norm_mantissa > b_norm_mantissa)
|
|
return TRUE;
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
static gboolean
|
|
float_ieee_11073_cmp_lt(const fvalue_t *a, const fvalue_t *b)
|
|
{
|
|
guint32 a_norm;
|
|
guint32 b_norm;
|
|
gint32 a_norm_mantissa;
|
|
gint32 b_norm_mantissa;
|
|
gint8 a_norm_exponent;
|
|
gint8 b_norm_exponent;
|
|
|
|
a_norm = float_to_normal_form(a->value.float_ieee_11073);
|
|
b_norm = float_to_normal_form(b->value.float_ieee_11073);
|
|
|
|
if (a_norm == b_norm)
|
|
return FALSE;
|
|
|
|
switch (a_norm) {
|
|
case FLOAT_VALUE_NAN:
|
|
case FLOAT_VALUE_NRES:
|
|
case FLOAT_VALUE_RFU:
|
|
case FLOAT_VALUE_INFINITY_PLUS:
|
|
return FALSE;
|
|
case FLOAT_VALUE_INFINITY_MINUS:
|
|
switch (b_norm) {
|
|
case FLOAT_VALUE_NAN:
|
|
case FLOAT_VALUE_NRES:
|
|
case FLOAT_VALUE_RFU:
|
|
case FLOAT_VALUE_INFINITY_MINUS: /* Dead, informative case */
|
|
return FALSE;
|
|
case FLOAT_VALUE_INFINITY_PLUS:
|
|
default:
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
a_norm_mantissa = a_norm & 0x00FFFFFF;
|
|
b_norm_mantissa = b_norm & 0x00FFFFFF;
|
|
if (a_norm & 0x00800000)
|
|
a_norm_mantissa |= 0xFF000000;
|
|
|
|
if (b_norm & 0x00800000)
|
|
b_norm_mantissa |= 0xFF000000;
|
|
|
|
a_norm_exponent = a_norm >> 24;
|
|
b_norm_exponent = b_norm >> 24;
|
|
|
|
if (a_norm_mantissa == b_norm_mantissa && a_norm_exponent < b_norm_exponent)
|
|
return TRUE;
|
|
|
|
if (a_norm_exponent == b_norm_exponent && a_norm_mantissa < b_norm_mantissa)
|
|
return TRUE;
|
|
|
|
if (a_norm_exponent < b_norm_exponent) {
|
|
guint8 exponent_difference;
|
|
|
|
exponent_difference = b_norm_exponent - a_norm_exponent;
|
|
|
|
if (exponent_difference >= 7)
|
|
return TRUE;
|
|
|
|
while (exponent_difference--) {
|
|
b_norm_mantissa *= 10;
|
|
}
|
|
} else {
|
|
guint8 exponent_difference;
|
|
|
|
exponent_difference = a_norm_exponent - b_norm_exponent;
|
|
|
|
if (exponent_difference >= 7)
|
|
return FALSE;
|
|
|
|
while (exponent_difference--) {
|
|
a_norm_mantissa *= 10;
|
|
}
|
|
}
|
|
|
|
if (a_norm_mantissa < b_norm_mantissa)
|
|
return TRUE;
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
static gboolean
|
|
float_ieee_11073_cmp_le(const fvalue_t *a, const fvalue_t *b)
|
|
{
|
|
guint32 a_norm;
|
|
guint32 b_norm;
|
|
gint32 a_norm_mantissa;
|
|
gint32 b_norm_mantissa;
|
|
gint8 a_norm_exponent;
|
|
gint8 b_norm_exponent;
|
|
|
|
a_norm = float_to_normal_form(a->value.float_ieee_11073);
|
|
b_norm = float_to_normal_form(b->value.float_ieee_11073);
|
|
|
|
if (a_norm == b_norm)
|
|
return TRUE;
|
|
|
|
switch (a_norm) {
|
|
case FLOAT_VALUE_NAN:
|
|
case FLOAT_VALUE_NRES:
|
|
case FLOAT_VALUE_RFU:
|
|
case FLOAT_VALUE_INFINITY_PLUS:
|
|
return FALSE;
|
|
case FLOAT_VALUE_INFINITY_MINUS:
|
|
switch (b_norm) {
|
|
case FLOAT_VALUE_NAN:
|
|
case FLOAT_VALUE_NRES:
|
|
case FLOAT_VALUE_RFU:
|
|
case FLOAT_VALUE_INFINITY_MINUS: /* Dead, informative case */
|
|
return FALSE;
|
|
case FLOAT_VALUE_INFINITY_PLUS:
|
|
default:
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
a_norm_mantissa = a_norm & 0x00FFFFFF;
|
|
b_norm_mantissa = b_norm & 0x00FFFFFF;
|
|
if (a_norm & 0x00800000)
|
|
a_norm_mantissa |= 0xFF000000;
|
|
|
|
if (b_norm & 0x00800000)
|
|
b_norm_mantissa |= 0xFF000000;
|
|
|
|
a_norm_exponent = a_norm >> 24;
|
|
b_norm_exponent = b_norm >> 24;
|
|
|
|
if (a_norm_mantissa == b_norm_mantissa && a_norm_exponent <= b_norm_exponent)
|
|
return TRUE;
|
|
|
|
if (a_norm_exponent == b_norm_exponent && a_norm_mantissa <= b_norm_mantissa)
|
|
return TRUE;
|
|
|
|
if (a_norm_exponent < b_norm_exponent) {
|
|
guint8 exponent_difference;
|
|
|
|
exponent_difference = b_norm_exponent - a_norm_exponent;
|
|
|
|
if (exponent_difference >= 7)
|
|
return TRUE;
|
|
|
|
while (exponent_difference--) {
|
|
b_norm_mantissa *= 10;
|
|
}
|
|
} else {
|
|
guint8 exponent_difference;
|
|
|
|
exponent_difference = a_norm_exponent - b_norm_exponent;
|
|
|
|
if (exponent_difference >= 7)
|
|
return FALSE;
|
|
|
|
while (exponent_difference--) {
|
|
a_norm_mantissa *= 10;
|
|
}
|
|
}
|
|
|
|
if (a_norm_mantissa < b_norm_mantissa)
|
|
return TRUE;
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
static gboolean
|
|
float_ieee_11073_cmp_bitwise_and(const fvalue_t *a, const fvalue_t *b)
|
|
{
|
|
return ((a->value.uinteger & b->value.uinteger) != 0);
|
|
}
|
|
|
|
/*============================================================================*/
|
|
|
|
void
|
|
ftype_register_ieee_11073_float(void)
|
|
{
|
|
/*
|
|
Size: 16bits = 2 octets
|
|
|
|
Exponent: 4 bits (signed integer - 2's complement)
|
|
Mantissa: 12 bits (signed integer - 2's complement)
|
|
Base: 10
|
|
|
|
x = M * (10 ^ E)
|
|
|
|
Exponent range: from -8 to 7
|
|
Mantissa range: from -2048 to 2047 (4 digits)
|
|
|
|
Special values:
|
|
+ INFINITY [exponent 0, mantissa +(2^11 -2) = 0x07FE]
|
|
NaN (Not a Number) [exponent 0, mantissa +(2^11 -1) = 0x07FF]
|
|
NRes (Not at this Resolution) [exponent 0, mantissa -(2^11) = 0x0800]
|
|
Reserved for future use [exponent 0, mantissa -(2^11 -1) = 0x0801]
|
|
- INFINITY [exponent 0, mantissa -(2^11 -2) = 0x0802]
|
|
|
|
Note:
|
|
be carefour when comparing: 1e == 10e-1 == 10e-2 == ... (solution: compare only if the lowest mantissa % 10 != 0)
|
|
|
|
Example: 114 is 0x0072
|
|
|
|
*/
|
|
static ftype_t sfloat_type = {
|
|
FT_IEEE_11073_SFLOAT, /* ftype */
|
|
"FT_IEEE_11073_SFLOAT", /* name */
|
|
"IEEE-11073 Floating point (16-bit)", /* pretty_name */
|
|
2, /* wire_size */
|
|
|
|
sfloat_ieee_11073_fvalue_new, /* new_value */
|
|
NULL, /* free_value */
|
|
sfloat_ieee_11073_val_from_unparsed, /* val_from_unparsed */
|
|
NULL, /* val_from_string */
|
|
sfloat_ieee_11073_val_to_repr, /* val_to_string_repr */
|
|
sfloat_ieee_11073_val_repr_len, /* len_string_repr */
|
|
|
|
{ .set_value_uinteger = sfloat_ieee_11073_value_set }, /* union set_value */
|
|
{ .get_value_uinteger = sfloat_ieee_11073_value_get }, /* union get_value */
|
|
|
|
sfloat_ieee_11073_cmp_eq,
|
|
sfloat_ieee_11073_cmp_ne,
|
|
sfloat_ieee_11073_cmp_gt,
|
|
sfloat_ieee_11073_cmp_ge,
|
|
sfloat_ieee_11073_cmp_lt,
|
|
sfloat_ieee_11073_cmp_le,
|
|
sfloat_ieee_11073_cmp_bitwise_and, /* cmp_bitwise_and */
|
|
NULL, /* cmp_contains */
|
|
NULL, /* cmp_matches */
|
|
|
|
NULL, /* len */
|
|
NULL, /* slice */
|
|
};
|
|
|
|
/*
|
|
Size: 32bits = 4 octets
|
|
|
|
Exponent: 1 octet (signed integer - 2's complement)
|
|
Mantissa: 3 octets (signed integer - 2's complement)
|
|
Base: 10
|
|
|
|
x = M * (10 ^ E)
|
|
|
|
Exponent range: from -128 to 127
|
|
Mantissa range: from -8388608 to 8388607 (7 digits)
|
|
|
|
Special values:
|
|
+ INFINITY [exponent 0, mantissa +(2^23 -2) = 0x007FFFFE]
|
|
NaN (Not a Number) [exponent 0, mantissa +(2^23 -1) = 0x007FFFFF]
|
|
NRes (Not at this Resolution) [exponent 0, mantissa -(2^23) = 0x00800000]
|
|
Reserved for future use [exponent 0, mantissa -(2^23-1) = 0x00800001]
|
|
- INFINITY [exponent 0, mantissa -(2^23 -2) = 0x00800002]
|
|
|
|
Note:
|
|
be carefour when comparing: 1e == 10e-1 == 10e-2 == ... (solution: compare only if the lowest mantissa % 10 != 0)
|
|
|
|
Example: 36.4 is 0xFF00016C
|
|
|
|
*/
|
|
|
|
static ftype_t float_type = {
|
|
FT_IEEE_11073_FLOAT, /* ftype */
|
|
"FT_IEEE_11073_FLOAT", /* name */
|
|
"IEEE-11073 Floating point (32-bit)", /* pretty_name */
|
|
4, /* wire_size */
|
|
|
|
float_ieee_11073_fvalue_new, /* new_value */
|
|
NULL, /* free_value */
|
|
float_ieee_11073_val_from_unparsed, /* val_from_unparsed */
|
|
NULL, /* val_from_string */
|
|
float_ieee_11073_val_to_repr, /* val_to_string_repr */
|
|
float_ieee_11073_val_repr_len, /* len_string_repr */
|
|
|
|
{ .set_value_uinteger = float_ieee_11073_value_set }, /* union set_value */
|
|
{ .get_value_uinteger = float_ieee_11073_value_get }, /* union get_value */
|
|
|
|
float_ieee_11073_cmp_eq,
|
|
float_ieee_11073_cmp_ne,
|
|
float_ieee_11073_cmp_gt,
|
|
float_ieee_11073_cmp_ge,
|
|
float_ieee_11073_cmp_lt,
|
|
float_ieee_11073_cmp_le,
|
|
float_ieee_11073_cmp_bitwise_and, /* cmp_bitwise_and */
|
|
NULL, /* cmp_contains */
|
|
NULL, /* cmp_matches */
|
|
|
|
NULL, /* len */
|
|
NULL, /* slice */
|
|
};
|
|
|
|
ftype_register(FT_IEEE_11073_SFLOAT, &sfloat_type);
|
|
ftype_register(FT_IEEE_11073_FLOAT, &float_type);
|
|
}
|
|
|
|
/*
|
|
* Editor modelines - http://www.wireshark.org/tools/modelines.html
|
|
*
|
|
* Local variables:
|
|
* c-basic-offset: 4
|
|
* tab-width: 8
|
|
* indent-tabs-mode: nil
|
|
* End:
|
|
*
|
|
* vi: set shiftwidth=4 tabstop=8 expandtab:
|
|
* :indentSize=4:tabSize=8:noTabs=true:
|
|
*/
|