C: Calculating the distance between 2 floats modulo 12
Asked Answered
E

5

14

I require a function dist( a, b ) // 0 ≤ a,b < 12 which returns the shortest (absolute ie +ve) distance ala clock arithmetic, using modulo 12.

So for example,

dist( 1, 2 )
 = dist( 2, 1 )
 = dist( 11, 0 )
 = dist( 0, 11 )
 = dist( 0.5, 11.5 )
 = 1

EDIT: while this can easily be done with a bit of hacking around, I feel that there must be some intuitive solution, may be using fmod and modulo 6

Erb answered 31/5, 2011 at 19:57 Comment(11)
Why the down votes? Are you people just looking at the first answer, and assuming this is trivial just because ChrisLegend declares it thus?Erb
@Ohmu It was because there was no question and no obvious attempt.Stalinsk
@Stalinsk you are probably right. Nevertheless I think anyone down-voting should consider... The question is implicit; no person of intelligence could miss it. Also I think it is bad practice to cloud the waters with a half-baked implementation. It doesn't work towards making a clean Q&A resource. For someone browsing questions several weeks from now, this formulation will articulate the topic precisely, without any valueless prancing around in order to avoid offending people's unconscious cultural sensibilities.Erb
For some perspective, consider what the tooltip says for the downvote arrow: This question does not show any research effort;.... What was your question? I require a function... [and some various examples] Was it clear that you've even attempted finding out a solution for yourself? Well you haven't shown it. What you effectively have done was a plzsendtehcodez question. This might not have been your intention, but you didn't make your case very clear.Chambray
Yeah I had reservations about posting an answer b/c it's a plzsendtehcodez, but it's a three-liner so w/e.Crouton
There is nothing wrong with plzsendtehcodez. So long as the question is decent, it only enriches SO as a resource. Sometimes I have asked and answered my own question. Sometimes someone has provided an answer I would not have thought of. Sometimes I have provided an answer to someone else's question because I find solving coding challenges inherently enjoyable. I did not need to post this question ( I ended up solving it myself, as per my answer below ), but it presents a nice little brainteaser, and a potentially useful resource, so I did.Erb
It is worth getting some perspective here -- why are people answering questions on this site? nobody is paying them. They are doing it for fun, solving puzzles as enjoyable as is sharing knowledge. If somebody is grumbling that I am breaking their back with my questions, they are simply expressing their own psychology. Why are they here in the first place?Erb
Well I see this site as a teaching environment, and an important rule of teaching/tutoring is to never give the full answer right away (aka give teh codez) because the student has to make an effort to find the answer, since if they don't, they aren't going to learn anything.Crouton
@trutheality, while you correctly identify a fundamental principle of teaching, to apply that to this site is just stupid. If everyone followed that principle this site would be a mess, and a completely useless resource. This is a site for questions and answers.Erb
@Ohmu if you look carefully you'll see that this principle is applied to a majority of plzsendtehcodez questions on this site.Crouton
If anyone is scratching their head on the top comment, within 10 min of posting this question received a single answer (since removed, hence this comment) saying 'this question is trivial, figure it out yourself' and at least 7 downvotes. Since my questioning this via a comment, it has received at least 5 up-votes, which seems to suggest people by and large are not in fact offended by the phrasing, leading me to suspect sheep mentality was indeed at work.Erb
E
18

Firstly, an optimal solution is nontrivial, it took a little thinking.

float distMod12(float a,float b)
{
    float diff = fabs( b - a );
    return ( diff < 6 ) ? diff : 12 - diff;
}

EDIT: Alternatively,

    return MIN( diff, 12 - diff ); // needs a MIN function

Complete code listing here: http://ideone.com/XxRIw

Erb answered 31/5, 2011 at 20:43 Comment(3)
Oh you're assuming that a and b are already >=0 and <12. Then you can get rid of amod and bmod in my solution and you end up with essentially the same.Crouton
@trutheality, I specified that criterion in my question.Erb
Implemented in PHP for 24: function distMod24($a,$b){ $diff = abs($b-$a); return ($diff<12) ? $diff : 24 - $diff; }Berget
U
7

If I read that correctly, a and b aren't negative, and they are smaller than 12.

#include <math.h>
#include <stdio.h>

double min( double a, double b ) {
   return a < b ? a : b;
}

double dist( double a, double b ) {
   return min( 
      fmod( 12+b-a, 12 ),
      fmod( 12+a-b, 12 )
   );
}

int main() {
   printf("%f\n", dist(1, 2));
   printf("%f\n", dist(2, 1));
   printf("%f\n", dist(11, 0));
   printf("%f\n", dist(0, 11));
   printf("%f\n", dist(0.5, 11.5));
   return 0;
}

which simplifies to

double dist( double a, double b ) {
   double diff = fmod( 12+a-b, 12 );
   return diff <= 6 ? diff : 12-diff;
}
Unholy answered 31/5, 2011 at 20:47 Comment(0)
C
6

Something like

float dist( float a, float b ){

   float amod, bmod;

   amod = fmod( a, 12 );
   bmod = fmod( b, 12 );

   if( amod < bmod ) return dist( bmod, amod );

   return min( amod-bmod, bmod-amod+12 );

}

Using the math library.

Crouton answered 31/5, 2011 at 20:4 Comment(2)
Thanks for posting code, intuitively I feel that there must be some more elegant solution ( which is why I posted in the first place ). But if there is I can't see it, and I can't see clearly that this is the tidiest solution.Erb
You're always going to have to compare two distances (the clockwise and the counterclockwise)Crouton
M
1

I think we can find the answer without any comparison, or branching. A one-liner. (IMO the most elegant way)

float dist(float a, float b){
    return abs(5.5-((b-(a-5.5))%12.0))
}

5.5 here is the middle point of the number line from 0 to 11.

After benchmarking though, it seems to be maybe very slightly slower than just doing it through MIN.

Magavern answered 3/12, 2022 at 23:29 Comment(0)
D
0

The absolute difference will always lie in the range [0,12). Subtracting 6 from this and taking the absolute value maps to the range [0,6]9 but "reversed" so subtract all from 6 to get

float dist(float a, float b){
    return 6-abs(abs(a-b)-6)
}

Docilu answered 31/3, 2024 at 23:38 Comment(1)
abs() returns int not floatPig

© 2022 - 2025 — McMap. All rights reserved.