Прошу прокомментировать код

Да, не подумал об этом. Спасибо!
К тому же 2 байта для fract многовато.

const uint8_t fract = abs(_value) % _del;

Я там “дописку” сделал как раз про то, что Вы сейчас написали :slight_smile: Обязательно прочитайте, не пропустите. И предложенный мною пример попробуйте. Это важно.

Результат: 6538.0
Я в шоке. Попробую сам разобраться…

Во! :slight_smile:

Я, с вашего позволения добавлю этот пример в ту статью про “карту граблей”. Очень уж он удачный получился. Ничего?

Конечно. Очень полезная статья про смешивание типов.

Вот тут немного запутался.
Типы unsigned и int занимают 2 байта, тип long - 4 байта.
Приведение unsigned к long во втором случае логично. Но, не понимаю, почему в первом случае приведение осуществляется именно к unsigned?

Когда переменная получает значение, которое непредставимо в её типе (например, переменная типа unsigned получает отрицательное значение или переменная типа int16 получает значение большее, чем 32767) – это приводит к неопределённому поведению (undefined behavior), потому лучший способ не пытаться понимать что там делается, т.к. делаться может всё, что угодно и объяснять это особого смысла не имеет.

В данном случае логика понятна, хотя она и ущербна. В некоторой степени отрицательные величины типа int являются легальными значениями для типа unsigned. В том смысле, что если присвоить отрицательный int переменной типа unsigned, а потом эту переменную присвоить снова переменной типа int, ничего не сломается.

Обратное неверно. Если отрицательный unsigned присвоить переменной типа int, а потом эту int-переменную присвоить переменной типа unsigned, то всё сломается.

Запустите и убедитесь сами
#include <Printing.h>

void setup(void) {
	Serial.begin(9600);
	{
		const int iv = -15;
		const unsigned uv = iv; // это легальная, обратимая операция
		const int ivv = uv;		// обращаем её
		printVarLn(ivv);		//	результат вернулся к изначальном -15
	}
	{
		const unsigned uv = -15;
		const int iv = uv; 		// это нелегальная, она необратима
		const unsigned uvv = iv;// обращаем её	
		printVarLn(uvv);		//	результат улетел куда попало
	}
}

void loop(void) {}

Таким образом, можно говорить, что тип unsigned - объемлющий по отношению к int. Потому к нему и преобразовывается.

Вот если было бы int32_t и uint16_t, то преобразование шло бы к знаковому потому, что на этот раз он “объемлющий”. В этом-то там и грабли, всегда трудно предсказать куда он там начнёт преобразовывать.

Спасибо! Исчерпывающе.