0.2.1 Adler

This commit is contained in:
rob tillaart 2022-09-21 09:34:38 +02:00
parent 3d74747999
commit 580182c3ad
13 changed files with 150 additions and 76 deletions

View File

@ -1,7 +1,7 @@
//
// FILE: Adler.cpp
// AUTHOR: Rob Tillaart
// VERSION: 0.2.0
// VERSION: 0.2.1
// DATE: 2022-01-27
// PURPOSE: Arduino Library for calculating Adler checksum
// URL: https://github.com/RobTillaart/Adler

View File

@ -2,7 +2,7 @@
//
// FILE: Adler.h
// AUTHOR: Rob Tillaart
// VERSION: 0.2.0
// VERSION: 0.2.1
// DATE: 2022-01-27
// PURPOSE: Arduino Library for calculating Adler checksum
// URL: https://github.com/RobTillaart/Adler
@ -12,7 +12,7 @@
#include "Arduino.h"
#define ADLER_LIB_VERSION (F("0.2.0"))
#define ADLER_LIB_VERSION (F("0.2.1"))
const uint32_t ADLER32_MOD_PRIME = 65521;

View File

@ -1,7 +1,7 @@
//
// FILE: Adler16.cpp
// AUTHOR: Rob Tillaart
// VERSION: 0.2.0
// VERSION: 0.2.1
// DATE: 2022-06-14
// PURPOSE: Arduino Library for calculating Adler-16 checksum
// URL: https://github.com/RobTillaart/Adler
@ -56,13 +56,14 @@ void Adler16::add(uint8_t value)
// straightforward going through the array.
// small footprint
void Adler16::add(uint8_t * array, uint16_t length)
// returns current Adler value
uint16_t Adler16::add(uint8_t * array, uint16_t length)
{
while (length--)
{
add(*array++);
}
return;
return (_s2 << 8) | _s1;
}
@ -71,7 +72,8 @@ void Adler16::add(uint8_t * array, uint16_t length)
// S2 grows quadratic
// only do modulo when S2 reaches halfway uint16_t
// and at the end of the loop.
void Adler16::addFast(uint8_t * array, uint16_t length)
// returns current Adler value
uint16_t Adler16::addFast(uint8_t * array, uint16_t length)
{
_count += length;
uint16_t s1 = _s1;
@ -92,6 +94,7 @@ void Adler16::addFast(uint8_t * array, uint16_t length)
}
_s1 = s1;
_s2 = s2;
return (s2 << 8) | s1;
}
@ -101,6 +104,12 @@ uint16_t Adler16::getAdler()
};
uint16_t Adler16::count()
{
return _count;
};
//////////////////////////////////////////////////////////////
//
// wrappers for strings.
@ -111,15 +120,15 @@ void Adler16::add(char value)
}
void Adler16::add(char * array, uint16_t length)
uint16_t Adler16::add(char * array, uint16_t length)
{
add((uint8_t *) array, length);
return add((uint8_t *) array, length);
}
void Adler16::addFast(char * array, uint16_t length)
uint16_t Adler16::addFast(char * array, uint16_t length)
{
addFast((uint8_t *) array, length);
return addFast((uint8_t *) array, length);
}

View File

@ -2,7 +2,7 @@
//
// FILE: Adler16.cpp
// AUTHOR: Rob Tillaart
// VERSION: 0.2.0
// VERSION: 0.2.1
// DATE: 2022-06-15
// PURPOSE: Arduino Library for calculating Adler-16 checksum
// URL: https://github.com/RobTillaart/Adler
@ -13,7 +13,7 @@
#include "Arduino.h"
#define ADLER16_LIB_VERSION (F("0.2.0"))
#define ADLER16_LIB_VERSION (F("0.2.1"))
// largest prime below 2^8
@ -24,21 +24,25 @@ class Adler16
public:
Adler16();
void begin(uint16_t s1 = 1, uint16_t s2 = 0);
void begin(uint16_t s1 = 1, uint16_t s2 = 0);
void add(uint8_t value);
void add(uint8_t * array, uint16_t length);
void add(uint8_t value);
// returns current Adler value
uint16_t add(uint8_t * array, uint16_t length);
// trade PROGMEM for speed
void addFast(uint8_t * array, uint16_t length);
// returns current Adler value
uint16_t addFast(uint8_t * array, uint16_t length);
// wrappers for strings
void add(char value);
void add(char * array, uint16_t length);
void addFast(char * array, uint16_t length);
void add(char value);
// returns current Adler value
uint16_t add(char * array, uint16_t length);
// returns current Adler value
uint16_t addFast(char * array, uint16_t length);
// returns current Adler value
uint16_t getAdler();
uint16_t count() { return _count; };
uint16_t count();
private:
uint16_t _s1;

View File

@ -1,7 +1,7 @@
//
// FILE: Adler32.cpp
// AUTHOR: Rob Tillaart
// VERSION: 0.2.0
// VERSION: 0.2.1
// DATE: 2022-01-27
// PURPOSE: Arduino Library for calculating Adler-32 checksum
// URL: https://github.com/RobTillaart/Adler
@ -55,13 +55,14 @@ void Adler32::add(uint8_t value)
// straightforward going through the array.
// small footprint.
void Adler32::add(uint8_t * array, uint16_t length)
// returns current Adler value
uint32_t Adler32::add(uint8_t * array, uint16_t length)
{
while (length--)
{
add(*array++);
}
return;
return (_s2 << 16) | _s1;
}
@ -70,7 +71,8 @@ void Adler32::add(uint8_t * array, uint16_t length)
// S2 grows quadratic
// only do modulo when S2 reaches halfway uint32_t
// and at the end of the loop.
void Adler32::addFast(uint8_t * array, uint16_t length)
// returns current Adler value
uint32_t Adler32::addFast(uint8_t * array, uint16_t length)
{
_count += length;
uint32_t s1 = _s1;
@ -91,6 +93,7 @@ void Adler32::addFast(uint8_t * array, uint16_t length)
}
_s1 = s1;
_s2 = s2;
return (s2 << 16) | s1;
}
@ -100,6 +103,11 @@ uint32_t Adler32::getAdler()
};
uint32_t Adler32::count()
{
return _count;
};
//////////////////////////////////////////////////////////////
//
@ -111,15 +119,15 @@ void Adler32::add(char value)
}
void Adler32::add(char * array, uint16_t length)
uint32_t Adler32::add(char * array, uint16_t length)
{
add((uint8_t *) array, length);
return add((uint8_t *) array, length);
}
void Adler32::addFast(char * array, uint16_t length)
uint32_t Adler32::addFast(char * array, uint16_t length)
{
addFast((uint8_t *) array, length);
return addFast((uint8_t *) array, length);
}

View File

@ -2,7 +2,7 @@
//
// FILE: Adler.h
// AUTHOR: Rob Tillaart
// VERSION: 0.2.0
// VERSION: 0.2.1
// DATE: 2022-01-27
// PURPOSE: Arduino Library for calculating Adler-32 checksum
// URL: https://github.com/RobTillaart/Adler
@ -12,7 +12,7 @@
#include "Arduino.h"
#define ADLER32_LIB_VERSION (F("0.2.0"))
#define ADLER32_LIB_VERSION (F("0.2.1"))
// largest prime below 2^16
@ -24,21 +24,25 @@ class Adler32
public:
Adler32();
void begin(uint32_t s1 = 1, uint32_t s2 = 0);
void begin(uint32_t s1 = 1, uint32_t s2 = 0);
void add(uint8_t value);
void add(uint8_t * array, uint16_t length);
void add(uint8_t value);
// returns current Adler value
uint32_t add(uint8_t * array, uint16_t length);
// trade PROGMEM for speed
void addFast(uint8_t * array, uint16_t length);
// returns current Adler value
uint32_t addFast(uint8_t * array, uint16_t length);
// wrappers for strings
void add(char value);
void add(char * array, uint16_t length);
void addFast(char * array, uint16_t length);
void add(char value);
// returns current Adler value
uint32_t add(char * array, uint16_t length);
// returns current Adler value
uint32_t addFast(char * array, uint16_t length);
uint32_t getAdler();
uint32_t count() { return _count; };
uint32_t count();
private:
uint32_t _s1;

View File

@ -5,6 +5,13 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](http://keepachangelog.com/)
and this project adheres to [Semantic Versioning](http://semver.org/).
## [0.2.1] - 2022-09-20
- return value added to **add(array)**
- return value added to **addFast(array, length)**
- update documentation (e.g. timing table).
- moved count() to .cpp
## [0.2.0] - 2022-06-15
- breaking change

View File

@ -15,9 +15,9 @@ Arduino Library for Adler-32 and experimental Adler-16 checksum.
This library provides a Adler32 checksum of a data array.
Furthermore since 0.2.0 an experimental Adler-16 implementation is added.
This one is often faster as it uses a smaller checksum than the Adler32,
and the price is that it is less sensitive than the Adler32.
Still it might have its niches where it will be useful.
This one is often faster as it uses a smaller checksum than the Adler32.
The price is that Adler16 is less sensitive than the Adler32.
Still it will have its niches where it will be useful.
Relates to https://github.com/RobTillaart/CRC
@ -46,10 +46,14 @@ The interface for the Adler16 is very similar.
optional setting start values for s1 and s2. Note this is not part of the standard.
This allows a restart from a specific index in a buffer.
- **void add(uint8_t value)** add a single value to the checksum.
- **void add(const uint8_t \* array, uint8_t length)** add an array of values to the checksum.
- **void addFast(const uint8_t \* array, uint8_t length)** add an array of values to the checksum. Is faster by trading PROGMEM for performance.
- **uint32_t add(const uint8_t \* array, uint8_t length)** add an array of values to the checksum.
Returns the current checksum.
- **uint32_t addFast(const uint8_t \* array, uint8_t length)** add an array of values to the checksum.
Is faster by trading PROGMEM for performance.
Returns the current checksum.
- **uint32_t getAdler()** get the current checksum.
- **uint32_t count()** get the number of items added. Merely a debugging feature, can overflow without affecting checksum.
- **uint32_t count()** get the number of items added. Merely a debugging feature,
can overflow without affecting checksum.
The class is typically used for streaming very large blocks of data,
optional with intermediate checksum tests.
@ -57,7 +61,8 @@ optional with intermediate checksum tests.
## Performance Adler32
Not tested ESP32 (and many other platforms) yet.
Only tested on UNO and ESP32 yet.
If you have data of other platforms, please let me know.
Numbers measured with **Adler32_performance.ino**.
@ -69,9 +74,9 @@ instead of a modulo.
| Version | Function | UNO 16 MHz | ESP32 240 MHz |
|:-------:|:---------|:----------:|:-------------:|
| 0.1.0 | add | 5.6 us | |
| 0.1.2 | add | 6.6 us | |
| 0.2.0 | add | 5.9 us | |
| 0.1.0 | add | 5.6 us | |
| 0.1.2 | add | 6.6 us | |
| 0.2.0 | add | 5.9 us | 1.7 us |
### add(lorem) 868 chars
@ -81,9 +86,10 @@ over the array and has a small footprint.
| Version | Function | UNO 16 MHz | ESP32 240 MHz |
|:-------:|:---------|:----------:|:-------------:|
| 0.1.0 | add | | |
| 0.1.2 | add | 6392 us | |
| 0.2.0 | add | 5748 us | |
| 0.1.0 | add | | |
| 0.1.2 | add | 6392 us | |
| 0.2.0 | add | 5748 us | 145 us |
Note: **add()** is about 6.6 us per byte.
@ -91,7 +97,7 @@ Note: **add()** is about 6.6 us per byte.
### addFast(lorem) 868 chars
The **addFast(array, length)** is faster than the
reference **add(array, length)** and uses 108 bytes more.
reference **add(array, length)** and uses 108 bytes more (UNO).
So the function has a larger footprint.
Depending on your needs, choose performance or footprint.
@ -102,15 +108,15 @@ See **Adler32_performance_addFast.ino**
|:-------:|:---------|:----------:|:-------------:|
| 0.1.0 | addFast | | |
| 0.1.2 | addFast | 1348 us | |
| 0.2.0 | addFast | 1348 us | |
| 0.2.0 | addFast | 1348 us | 66 us |
Note: **addFast()** is less than 2 us per byte.
## Performance Adler16
Not tested ESP32 (and many other platforms) yet.
Only tested on UNO and ESP32 yet.
If you have data of other platforms, please let me know.
Numbers measured with **Adler16_performance.ino**.
@ -122,7 +128,7 @@ instead of a modulo.
| Version | Function | UNO 16 MHz | ESP32 240 MHz |
|:-------:|:---------|:----------:|:-------------:|
| 0.2.0 | add | 4.0 us | |
| 0.2.0 | add | 4.0 us | 1.8 us |
The per byte performance of the Adler16 (on UNO) is faster
than the Adler32 **add(value)**. The reason is that a 16 bit
@ -136,7 +142,7 @@ over the array and has a small footprint.
| Version | Function | UNO 16 MHz | ESP32 240 MHz |
|:-------:|:---------|:----------:|:-------------:|
| 0.2.0 | add | 4040 us | |
| 0.2.0 | add | 4040 us | 160 us |
Note: **add()** is about 6.6 us per byte.
@ -148,7 +154,7 @@ reference **add(array, length)**.
| Version | Function | UNO 16 MHz | ESP32 240 MHz |
|:-------:|:---------|:----------:|:-------------:|
| 0.2.0 | addFast | 1968 us | |
| 0.2.0 | addFast | 1968 us | 79 us |
The gain of the faster 16 bit modulo meets the frequency of
doing the modulo more often.
@ -169,7 +175,8 @@ Think of packets in a network, records in a database, or a checksum for an confi
### Performance
Not tested ESP32 (and many other platforms) yet.
Only tested on UNO and ESP32 yet.
If you have data of other platforms, please let me know.
Numbers measured with **Adler_performance.ino**.
@ -179,18 +186,20 @@ Lorem Ipsum text = 868 bytes.
|:-------:|:---------|:----------:|:-------------:|
| 0.1.0 | Adler32 | 1116 us | |
| 0.1.2 | Adler32 | 1116 us | |
| 0.2.0 | Adler32 | 1116 us | |
| 0.2.0 | Adler16 | 1736 us | |
| 0.2.0 | Adler32 | 1116 us | 60 us |
| 0.2.0 | Adler16 | 1736 us | 75 us |
#### UNO
Adler32 average 1116 / 868 = 1.29 us per byte.
Adler16 average 1736 / 868 = 2.00 us per byte. (~1.5x slower !)
Adler16 does more often the modulo math as it reaches halfway uint16_t
faster than Adler32 reaches halfway uint32_t.
As the Adler16 is less performant as the Adler32, it is often the best to use
the 32 bit version.
As the Adler16 is less performant as the Adler32 (on all tested platforms),
it is often the best to use the 32 bit version.
## Operation
@ -200,17 +209,20 @@ See examples.
## Future
- return values for **add(array)** and **addFast(array)**
- updated checksum?
- not for **add(value)** as that would create quite some overhead.
- Adler64 ?
- would need a large prime (which)
- would need a large prime (which) => 4294967291
- max uint32_t = 4.294.967.296
- max uint32_t prime = 4.294.967.291
- need printHelpers library for printing.
- only on request.
#### Wont
- do the string wrappers need strlen() ? parameter.
- yes, as string can be processed partially.
- no return value for **add(value)**
- would create too much overhead for repeated calls.

View File

@ -0,0 +1,25 @@
Adler32_performance
ADLER32_LIB_VERSION: 0.2.0
randomtime: 6949
total: 8639
1e4 x add: 1690
checksum: 2580568639
total: 224706
1e6 x add: 217757
checksum: 237492440
LENGTH LOREM: 868
lorem 1: 198 checksum: 3972480156
lorem 2: 145 checksum: 3972480156
lorem 3: 66 checksum: 3972480156
LENGTH HELLO: 11
hello 1: 3 checksum: 436929629
hello 2: 3 checksum: 436929629
hello 3: 3 checksum: 436929629

View File

@ -15,7 +15,7 @@
"type": "git",
"url": "https://github.com/RobTillaart/Adler.git"
},
"version": "0.2.0",
"version": "0.2.1",
"license": "MIT",
"frameworks": "arduino",
"platforms": "*",

View File

@ -1,5 +1,5 @@
name=Adler
version=0.2.0
version=0.2.1
author=Rob Tillaart <rob.tillaart@gmail.com>
maintainer=Rob Tillaart <rob.tillaart@gmail.com>
sentence=Arduino Library for calculating Adler-32 and Adler-16 checksum.

View File

@ -74,14 +74,17 @@ unittest(test_ADLER16_lorem)
ad16.add(lorem[i]);
}
assertEqual(57303, ad16.getAdler());
assertEqual(868, ad16.count());
ad16.begin();
ad16.add(lorem, strlen(lorem));
assertEqual(57303, ad16.add(lorem, strlen(lorem)));
assertEqual(57303, ad16.getAdler());
assertEqual(868, ad16.count());
ad16.begin();
ad16.addFast(lorem, strlen(lorem));
assertEqual(57303, ad16.addFast(lorem, strlen(lorem)));
assertEqual(57303, ad16.getAdler());
assertEqual(868, ad16.count());
}

View File

@ -74,15 +74,17 @@ unittest(test_ADLER32_lorem)
ad32.add(lorem[i]);
}
assertEqual(3972480156, ad32.getAdler());
assertEqual(868, ad32.count());
ad32.begin();
ad32.add(lorem, strlen(lorem));
assertEqual(3972480156, ad32.add(lorem, strlen(lorem)));
assertEqual(3972480156, ad32.getAdler());
assertEqual(868, ad32.count());
ad32.begin();
ad32.addFast(lorem, strlen(lorem));
assertEqual(3972480156, ad32.addFast(lorem, strlen(lorem)));
assertEqual(3972480156, ad32.getAdler());
assertEqual(868, ad32.count());
}