> On Jan 27, 2023, at 2:46 AM, Tagir Valeev <amae...@gmail.com> wrote: > > … >> >> >> public static int clamp(long value, int min, int max) >> public static long clamp(long value, long min, long max) >> public static double clamp(double value, double min, double max) >> public static float clamp(double value, float min, float max) > > I really like the idea of int clamp(long value, int min, int max), as > this makes the method much more useful. On the other hand, I have > doubles about > float clamp(double value, float min, float max), as it could be called > accidentally and we will have accidental precision loss. E.g., imagine > the following code:
That was a typo. Oops, sorry. All I am trying to suggest is to widen both the first argument and the return value to long or double. > > // bounds are declared as floats for some reason > // this usually doesn't matter, as these numbers are exact in float > and in double > float lower = 0.0f; > float upper = 10.0f; > > double v = 1/3.; > System.out.println(v); > v = Math.clamp(v, lower, upper); // oops! > System.out.println(v); > > Having float clamp(double, float, float), this method will be linked > here, resulting in accidental precision loss. The output is: > 0.3333333333333333 > 0.3333333432674408 > > Given that float type is rarely used, I'd stick to the following signatures: > public static int clamp(long value, int min, int max) > public static long clamp(long value, long min, long max) > public static double clamp(double value, double min, double max) > public static float clamp(float value, float min, float max) > >> I thought about cross-domain clamps, which preserve 64 bit >> precision and double range at the same time in different places: >> >> public static long clamp(long value, double min, double max) >> public static long clamp(double value, long min, long max) > > This is even more dangerous, as simply calling > double value = ... > value = clamp(value, 0, 1); // not 0.0 and 1.0 > you will get 0 instead of the original value that fits the range. > I imagine that many people will step on this. If these methods are desired, > it would be better to name them differently, to avoid overload ambiguity. > For now, I would avoid this. Of course. Widen the return if you widen the first argument. Then it works out. > >> The subexpression max-min never overflows, when it >> is regarded as an unsigned number, and the “>>>1” >> immediately converts that unsigned number into the >> correctly signed positive number. That’s the only >> way to avoid overflow for all inputs. The third >> idiom above (the “smartest” of the three) will fail, >> for example, if you feed it negative values. >> For some uses that is OK, but for others it isn’t. >> >> public static int midpoint(int min, int max) >> public static long midpoint(long min, long max) >> public static double midpoint(double min, double max) >> public static float midpoint(float min, float max) > > midpoint is another great idea, I like it! Could also be considered > separately. > > With best regards, > Tagir Valeev.