Я думаю, что лучший способ достичь этого - полагаться на тот факт, что в соответствии со стандартом IEEE 754 целочисленное представление битов с плавающей запятой лексикографически упорядочено как целое число из 2-х дополнений.
т.е. Вы можете просто добавить один ulp (единицы на последнем месте), чтобы получить следующее представление с плавающей запятой (которое всегда будет немного больше, чем ваш порог, если он меньше, так как ошибка округления не более 1/2 ulp)
, например
float floatValue = 7.f/10;
std::cout << std::setprecision(20) << floatValue << std::endl;
int asInt = *(int*)&floatValue;
asInt += 1;
floatValue = *(float*)&asInt;
std::cout << floatValue << std::endl;
отпечатков (в моей системе)
0.69999998807907104492
0.70000004768371582031
Чтобы узнать, когда вам нужно добавить один ульп, вам нужно полагаться на разницу floor
и округленное floor
if (std::floor(floatValue * 100.) != std::floor(floatValue * 100. + 0.5)) {
int asInt = *(int*)&floatValue;
asInt += 1;
floatValue = *(float*)&asInt;
}
Правильно конвертирует 0,69 ... в 0,70 ..., но оставляет 0,80 ... в покое.
Обратите внимание, что число с плавающей запятой увеличивается до двойного с помощью умножения на 100.
до применения floor
.
Если вы этого не сделаете, вы рискуете оказаться в ситуации, которая для
7.f/10.f * 100.f
Представление с плавающей точкой (с ограниченной точностью) будет 70,00 ...