Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/arduino-lint.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ jobs:
runs-on: ubuntu-latest
timeout-minutes: 5
steps:
- uses: actions/checkout@v5
- uses: actions/checkout@v6
- uses: arduino/arduino-lint-action@v2
with:
library-manager: update
Expand Down
3 changes: 1 addition & 2 deletions .github/workflows/arduino_test_runner.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,8 @@ jobs:
runTest:
runs-on: ubuntu-latest
timeout-minutes: 20

steps:
- uses: actions/checkout@v5
- uses: actions/checkout@v6
- uses: ruby/setup-ruby@v1
with:
ruby-version: 2.6
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/jsoncheck.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ jobs:
runs-on: ubuntu-latest
timeout-minutes: 5
steps:
- uses: actions/checkout@v5
- uses: actions/checkout@v6
- name: json-syntax-check
uses: limitusus/json-syntax-check@v2
with:
Expand Down
8 changes: 8 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,14 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/)
and this project adheres to [Semantic Versioning](http://semver.org/).


## [0.4.0] - 2026-06-15
- fix **sign()** for -0 (0x8000)
- update unit test
- update GitHub actions
- minor edits

----

## [0.3.1] - 2025-10-13
- update GitHub actions
- update examples
Expand Down
2 changes: 1 addition & 1 deletion LICENSE
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
MIT License

Copyright (c) 2015-2025 Rob Tillaart
Copyright (c) 2015-2026 Rob Tillaart

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
Expand Down
72 changes: 42 additions & 30 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,57 +24,65 @@ The primary usage of the float16 data type is to efficiently store and transport
a floating point number. As it uses only 2 bytes where float and double have typical
4 and 8 bytes, gains can be made at the price of range and precision.

Note that float16 only has ~3 significant digits.
Note that a float16 only has ~3 significant digits.

To print a float16, one need to convert it with toFloat(), toDouble() or toString(decimals).
To print a float16, one need to convert it with toFloat(), toDouble() or toString(decimals).
The latter allows concatenation and further conversion to an char array.

In pre 0.3.0 version the Printable interface was implemented, but it has been removed
as it caused excessive memory usage when declaring arrays of float16.

Feedback as always is welcome.


### ARM alternative half-precision

-https://en.wikipedia.org/wiki/Half-precision_floating-point_format#ARM_alternative_half-precision
- https://en.wikipedia.org/wiki/Half-precision_floating-point_format#ARM_alternative_half-precision

_ARM processors support (via a floating point control register bit)
an "alternative half-precision" format, which does away with the
special case for an exponent value of 31 (111112).[10] It is almost
identical to the IEEE format, but there is no encoding for infinity or NaNs;
_ARM processors support (via a floating point control register bit)
an "alternative half-precision" format, which does away with the
special case for an exponent value of 31 (111112).[10] It is almost
identical to the IEEE format, but there is no encoding for infinity or NaNs;
instead, an exponent of 31 encodes normalized numbers in the range 65536 to 131008._

Implemented in https://github.com/RobTillaart/float16ext class.


### Difference with float16 and float16ext

The float16ext library has an extended range as it supports values from +- 65504
The float16ext library has an extended range as it supports values from +- 65504
to +- 131008.

The float16ext does not support INF, -INF and NAN. These values are mapped upon
the largest positive, the largest negative and the largest positive number.

The -0 and 0 values will both exist.


Although they share a lot of code float16 and float16ext should not be mixed.
In the future these libraries might merge / derive one from the other.


### Breaking change 0.4.0

Version 0.4.0 has fixed sign() which gave incorrect results for 0 and -0.


### Breaking change 0.3.0

Version 0.3.0 has a breaking change. The **Printable** interface is removed as
Version 0.3.0 has a breaking change. The **Printable** interface is removed as
it causes larger than expected arrays of float 16 (See #16). On ESP8266 every
float16 object was 8 bytes and on AVR it was 5 bytes instead of the expected 2 bytes.

To support printing the class added two new conversion functions:

```cpp
f16.toFloat();
f16.toString(decimals);

Serial.println(f16.toFloat(), 4);
Serial.println(f16.toString(4));
```

This keeps printing relative easy.

The footprint of the library is now smaller and one can now create compact array's
Expand All @@ -85,15 +93,15 @@ of float16 elements using only 2 bytes per element.

Version 0.2.0 has a breaking change as a conversion bug has been found.
See for details in issue #10.
For some specific values the mantissa overflowed when the float 16 was
For some specific values the mantissa overflowed when the float 16 was
assigned a value to. This overflow was not detected / corrected.

During the analysis of this bug it became clear that the sub-normal numbers
During the analysis of this bug it became clear that the sub-normal numbers
were also not implemented correctly. This is fixed too in 0.2.0.

There is still an issue with 0 versus -0 (sign gets lost in conversion).

**This makes all pre-0.2.0 version obsolete.**
**This makes all pre-0.2.0 versions obsolete.**


## Specifications
Expand All @@ -108,6 +116,7 @@ There is still an issue with 0 versus -0 (sign gets lost in conversion).
| minimum | ±5.96046 E−8 | smallest number.
| | ±1.0009765625 | 1 + 2^−10 = smallest number larger than 1.
| maximum | ±65504 |
| range | | 12 orders of magnitude
| | |

± = ALT 0177
Expand All @@ -119,24 +128,25 @@ Source: https://en.wikipedia.org/wiki/Half-precision_floating-point_format

```cpp
/*
SIGN EXP MANTISSA
0 01111 0000000000 = 1
0 01111 0000000001 = 1 + 2−10 = 1.0009765625 (next smallest float after 1)
1 10000 0000000000 = −2
SIGN EXPONENT MANTISSA
0 01111 0000000000 = 1
0 01111 0000000001 = 1 + 2−10 = 1.0009765625 (next smallest float after 1)
1 10000 0000000000 = −2

0 11110 1111111111 = 65504 (max half precision)
0 11110 1111111111 = 65504 (max float16)
0 11111 1111111111 = 131008 (max float16ext)

0 00001 0000000000 = 2−14 ≈ 6.10352 × 10−5 (minimum positive normal)
0 00000 1111111111 = 2−14 - 2−24 ≈ 6.09756 × 10−5 (maximum subnormal)
0 00000 0000000001 = 2−24 ≈ 5.96046 × 10−8 (minimum positive subnormal)
0 00001 0000000000 = 2−14 ≈ 6.10352 × 10−5 (minimum positive normal)
0 00000 1111111111 = 2−14 - 2−24 ≈ 6.09756 × 10−5 (maximum subnormal)
0 00000 0000000001 = 2−24 ≈ 5.96046 × 10−8 (minimum positive subnormal)

0 00000 0000000000 = 0
1 00000 0000000000 = −0
0 00000 0000000000 = 0
1 00000 0000000000 = −0

0 11111 0000000000 = infinity
1 11111 0000000000 = −infinity
0 11111 0000000000 = infinity
1 11111 0000000000 = −infinity

0 01101 0101010101 = 0.333251953125 ≈ 1/3
0 01101 0101010101 = 0.333251953125 ≈ 1/3
*/
```

Expand All @@ -147,6 +157,7 @@ Source: https://en.wikipedia.org/wiki/Half-precision_floating-point_format
- https://github.com/RobTillaart/float16
- https://github.com/RobTillaart/float16ext
- https://github.com/RobTillaart/fraction
- https://github.com/RobTillaart/printHelpers - scientific format a.o.
- https://en.wikipedia.org/wiki/Half-precision_floating-point_format


Expand All @@ -163,7 +174,7 @@ Source: https://en.wikipedia.org/wiki/Half-precision_floating-point_format
- **float16(const float16 &f)** copy constructor.


### Conversion
### Conversion / printing

- **double toDouble(void)** convert value to double or float (if the same e.g. UNO).
- **float toFloat(void)** convert value to float.
Expand All @@ -182,7 +193,7 @@ To serialize the internal format e.g. to disk, two helper functions are availabl

### Compare

The library implement the standard compare functions.
The library implement the standard compare functions.
These are optimized, so it is fast to compare 2 float16 values.

Note: comparison with a float or double always include a conversion.
Expand Down Expand Up @@ -217,7 +228,7 @@ Negation operator.
Math helpers.
- **int sign()** returns 1 == positive, 0 == zero, -1 == negative.
- **bool isZero()** returns true if zero. slightly faster than **sign()**.
- **bool isNaN()** returns true if value is not a number.
- **bool isNaN()** returns true if value is not a number.
- **bool isInf()** returns true if value is ± infinite.
- **bool isPosInf()** returns true if value is + infinite.
- **bool isNegInf()** returns true if value is - infinite.
Expand All @@ -231,7 +242,8 @@ Math helpers.

#### Should

- how to handle 0 == -0 (0x0000 == 0x8000)
- how to handle 0 == -0 (0x0000 == 0x8000) or (0x8000 == 0x0000)
- if ((_value & 0x7FFF) == 0x0000) return (f._value & 0x7FFF) == 0x0000;

#### Could

Expand Down
4 changes: 2 additions & 2 deletions examples/float16_sizeof_array/float16_sizeof_array.ino
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
// AUTHOR: Rob Tillaart
// PURPOSE: test float16 size
// URL: https://github.com/RobTillaart/float16
// See #12
// See issue #12

#include "Arduino.h"
#include "float16.h"
Expand Down Expand Up @@ -35,7 +35,7 @@ void setup()
Serial.println(sizeof(test32[0]));
Serial.println();

// set some values to make sure the compiler doesn't optimise out the arrays.
// set some values to make sure the compiler doesn't optimise out the arrays.
test16[5] = 32;
test32[4] = 32;

Expand Down
16 changes: 15 additions & 1 deletion examples/float16_test0/float16_test0.ino
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,20 @@ void setup()

Serial.println("Start ");

// // sign test
// float16 a(0);
// Serial.println(a.sign());
// Serial.println(a.getBinary(), HEX);
// a.setBinary(0x8000);
// Serial.println(a.sign());
// a.setBinary(0x0000);
// Serial.println(a.sign());
// a.setBinary(0x8100);
// Serial.println(a.sign());
// a.setBinary(0x0100);
// Serial.println(a.sign());
// while (1);

Serial.println();

test_constructors();
Expand Down Expand Up @@ -133,7 +147,7 @@ void test_numbers()
float16 c(1 / 2000.0);
Serial.println(c.toDouble(), 9);

c = 1/3.0;
c = 1 / 3.0;
Serial.println(c.toDouble(), 9);

float16 d(1);
Expand Down
14 changes: 9 additions & 5 deletions float16.cpp
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
//
// FILE: float16.cpp
// AUTHOR: Rob Tillaart
// VERSION: 0.3.1
// VERSION: 0.4.0
// DATE: 2015-03-10
// PURPOSE: library for Float16s for Arduino
// URL: http://en.wikipedia.org/wiki/Half-precision_floating-point_format
Expand Down Expand Up @@ -43,6 +43,7 @@ String float16::toString(unsigned int decimals) const
//
bool float16::operator == (const float16 &f)
{
// if ((_value & 0x7FFF) == 0x0000) return (f._value & 0x7FFF) == 0x0000;
return (_value == f._value);
}

Expand Down Expand Up @@ -151,9 +152,12 @@ float16& float16::operator /= (const float16 &f)
//
int float16::sign()
{
if (_value & 0x8000) return -1;
if (_value & 0xFFFF) return 1;
return 0;
// zero test matches 0x8000 too
if ((_value & 0x7FFF) == 0x0000) return 0;
// positive test including positive infinity
if (_value <= 0x7FFF) return 1;
// remaining is negative
return -1;
}

bool float16::isZero()
Expand Down Expand Up @@ -225,7 +229,7 @@ float float16::f16tof32(uint16_t _value) const

uint16_t float16::f32tof16(float f) const
{
uint32_t t = *(uint32_t *) &f;
uint32_t t = *((uint32_t *) &f);
// man bits = 10; but we keep 11 for rounding
uint16_t man = (t & 0x007FFFFF) >> 12;
int16_t exp = (t & 0x7F800000) >> 23;
Expand Down
4 changes: 2 additions & 2 deletions float16.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
//
// FILE: float16.h
// AUTHOR: Rob Tillaart
// VERSION: 0.3.1
// VERSION: 0.4.0
// DATE: 2015-03-10
// PURPOSE: Arduino library to implement float16 data type.
// half-precision floating point format,
Expand All @@ -12,7 +12,7 @@

#include "Arduino.h"

#define FLOAT16_LIB_VERSION (F("0.3.1"))
#define FLOAT16_LIB_VERSION (F("0.4.0"))


class float16
Expand Down
2 changes: 1 addition & 1 deletion library.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
"type": "git",
"url": "https://github.com/RobTillaart/float16.git"
},
"version": "0.3.1",
"version": "0.4.0",
"license": "MIT",
"frameworks": "*",
"platforms": "*",
Expand Down
2 changes: 1 addition & 1 deletion library.properties
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
name=float16
version=0.3.1
version=0.4.0
author=Rob Tillaart <rob.tillaart@gmail.com>
maintainer=Rob Tillaart <rob.tillaart@gmail.com>
sentence=Arduino library to implement float16 data type.
Expand Down
22 changes: 22 additions & 0 deletions test/unit_test_001.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,28 @@ unittest(test_sizeof)
}


unittest(test_sign)
{
float16 a(0);
assertEqual( 0, a.sign());

a.setBinary(0x0000); // +0
assertEqual( 0, a.sign());
a.setBinary(0x8000); // -0
assertEqual( 0, a.sign());

a.setBinary(0x0100);
assertEqual( 1, a.sign());
a.setBinary(0x8100);
assertEqual(-1, a.sign());

a.setBinary(0x7C00); // positive infinity
assertEqual( 1, a.sign());
a.setBinary(0xFC00); // negative infinity
assertEqual(-1, a.sign());
}


unittest(test_compare_equal)
{
float16 a(1);
Expand Down
Loading