0

I'm using SFML library for a game application with moving objects. In the game, I have a ball object and I need to make sure that the ball's offset on the Y-axis each move is at least 0.1 (or -0.1)

Here's the code I'm using now:

if (offset.y < 0.0 && offset.y > -0.1) offset.y = -0.1;
if (offset.y > 0.0 && offset.y < 0.1) offset.y = 0.1;

Is there an easier/prettier way to accomplish that?

Edit: As pointed out by the comments, code should include 0.0 case

if (offset.y < 0.0 && offset.y > -0.1) offset.y = -0.1;
if (offset.y >= 0.0 && offset.y < 0.1) offset.y = 0.1;
Shlomo Gottlieb
  • 519
  • 5
  • 11
  • 1
    What if it is *exactly* 0.0? – Bob__ Jun 20 '19 at 21:04
  • 4
    Do note that `.1` cant actually be represented in a floating point type. If you want to step by an even interval then I would suggest using an integer type and just scale it by the appropriate factor. – NathanOliver Jun 20 '19 at 21:04
  • 3
    Well, you could play games with `abs()`, `min()` and `sign()`, and reduce this to one expression: `min(abs(offset.y)+.01), .01)*sign(offset.y)` (with appropriate sprinkles of `std::`, includes, and "sign" [borrowed from this question](https://stackoverflow.com/questions/1903954/is-there-a-standard-sign-function-signum-sgn-in-c-c)). But you will accomplish very little that's actually useful. Personally, I find the shown code more readable than this abomination. Unfortunately, this is **primarily opinion-based**. – Sam Varshavchik Jun 20 '19 at 21:05
  • One of those should be non-strict (logically), but other than that, I think this is clear, readable and correct code - beside the obvious fact that .1 is in not representable in IEEE 754, but I imagine, you are ok with it. – SergeyA Jun 20 '19 at 21:09
  • @SamVarshavchik Nice combination, but I agree it's not so readable. – Shlomo Gottlieb Jun 20 '19 at 21:12
  • Too bad there isn't a syntax like `if (is(offset.y).between(0.0, -0.1)) ...` Hmmm, that might not be too difficult to make. – Eljay Jun 20 '19 at 21:16
  • Doesn't this reverse the direction of the ball? – Avin Kavish Jun 20 '19 at 21:20
  • You may always use some simple expression like this: `void magic(float& f) { *((int*)&f) = ((f!=-0.0f)&&((((*(((char*)&f)+3) & 0x7F) == 0x3d)&&((*((int*)&f) & 0x00FFFFFF) <= 0xcccccd))||((*(((char*)&f)+3) & 0x7F) < 0x3d)))?((*(((char*)&f)+3)&0x80)<<24) | 0x3dcccccd:*((int*)&f); }` – Logman Jun 20 '19 at 22:38

4 Answers4

4

Just use std::abs() and std::copysign():

if (std::abs(offset.y) < .1)
    offset.y = std::copysign(.1, offset.y);

Preserving the sign of zero any other way is difficult.

Though, consider whether you cannot use an integral model instead; .1 cannot be exactly represented as binary floating point.

Lightness Races in Orbit
  • 378,754
  • 76
  • 643
  • 1,055
Deduplicator
  • 44,692
  • 7
  • 66
  • 118
2

What would be "easier or prettier" is highly opinion based, I'm afraid, but you could start by wrapping the logic into a function with a meaningful name (hopefully better than mine).

double at_least(double min_value, double x)
{
    if (x < 0.0 && x > -min_value)
        return -min_value;
    if (x >= 0.0 && x < min_value)
        return min_value;
    return x;
}

Then, you could experiment some other alternatives:

#include <cmath>
#include <algorithm>

double at_least(double min_value, double x)
{
    return std::copysign(std::max(min_value, std::abs(x)), x);
}

Or this one

double at_least(double min_value, double x)
{
    if (x < 0.0 )
        return std::min(-min_value, x);
    else
        return std::max(min_value, x);
}

After testing the correctness of each one, you could also profile them, if performances are important for your task. See e.g. those quick benchmarks:

http://quick-bench.com/AXt8U9vKg-75XXOFMyCK0g14RyQ
http://quick-bench.com/_nfoT0BKsAvh6QDzAWc-cX3_KYU

Bob__
  • 12,361
  • 3
  • 28
  • 42
1

If you only need 1 digit after decimal point, you can use a scaled integer. To convert it to a floating point number you multiply it by 0.1. To convert a floating point number to the integer you multiply it by 10 and round to the nearest integer.

Maxim Egorushkin
  • 131,725
  • 17
  • 180
  • 271
0

I think it's good enough . It looks clear . You can play with e.g functions from cmath such as abs,signbit . Or wrapping it to new function- But I can't see any point in doing that

Takahashi
  • 65
  • 2
  • 9