с плавающей точкой — странная ошибка потолка в переполнении стека

Здравствуйте, у меня есть некоторые трудности с функцией ceil в c ++:

У меня есть регулярная сетка точек, и мне нужно выполнить интерполяцию по ней, чтобы вычислить z-значения набора точек.

Чтобы сделать это, мне нужно для каждой вычисленной точки получить ближайшие точки на сетке. Я делаю это так:

y1 = dy*floor(p.y/dy);
y2 = dy*ceil(p.y/dy);

где dy — пространство между двумя точками сетки. (y1, p.y и dy двойные)
Если я отображу результаты с помощью

cout << static_cast<double>(p.y/dy) << ": " << y1 << ", " << y2 << endl;

Я получил эти странные результаты:

0: 0, 0
1: 0.1, 0.1
2: 0.2, 0.2
3: 0.3, 0.4

Три первых результата в порядке, но последний неверен и делает утверждение ошибочным.

Хотелось бы узнать, откуда появилась эта странная ошибка и как ее избежать.
Благодарю.

Я прошу прощения за мой английский

РЕДАКТИРОВАТЬ

Я вызываю функцию с dy = 0.1, но во время выполнения она принимает следующее значение dy = 0.10000000000000001.
p.y инициализируется так:

 const uint N = round((x2 - x1) / dx2);
const uint M = round((y2 - y1) / dy2);

double p = persistence;
double n = number_of_octaves;

// generation of the points where the perlin noise is generated
std::vector<Vertex3d> ret;
std::vector<Vertex3d> dummy;
for (uint i=0;i<=N;++i)
{
for (uint j=0;j<=M;++j)
{
ret.push_back({.x = i*dx2, .y=j*dy2, .z=0});
dummy.push_back({.x = i*dx2, .y=j*dy2, .z=0});
}
}

где x1 = 0 и x2 = 1 (по данным gdb)

2

Решение

Учитывая ваши результаты, я полагаю, dy равно 0.1,

Ваши результаты не ошибаются. Если у вас есть 0.3 < p.y < 0.4 тогда у вас будет 3 < p.y/dy < 4 Итак ceil будет 4 и floor будет 3,

Может быть, вы запутались, потому что где-то еще в вашем коде вы установили p.y до 0,3 или 0,4. Вы должны знать, что поплавки не так точно. Это означает, что даже если вы установите p.y = 0.3 это может иметь значение 0.30000001 или что-то подобное, вызывая вашу проблему.

1

Другие решения

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

Вот классическое обсуждение арифметики с плавающей точкой.

1

Это выглядит просто как случай ошибок округления для арифметики с плавающей запятой.

Возможно, в последнем случае результат равен 3.00000000000001, поэтому его потолок равен 4, а не 3 (а затем умножается на 0,1).

-1