Angle between the hands on a clock

36

4

Given the time in 24 hour format (2359 = 11:59pm) return the angle between the minute and hour hands on a standard clock (on the face plane, so don't just output 0).

Angles are to be returned in the unit of your choice, should be the smallest possible, and should be a positive number (negative angle converted to a positive value), i.e. you will never have an answer greater than 180 degrees or pi radians.

Some examples to check against (in degrees)

  • 0000 = 0.0
  • 0010 = 55.0
  • 0020 = 110.0
  • 0030 = 165.0
  • 0040 = 140.0
  • 0050 = 85.0
  • 0150 = 115.0
  • 0240 = 160.0
  • 0725 = 72.5
  • 1020 = 170.0
  • 1350 = 115.0
  • 1725 = 12.5

Note: There are a few that have rounding errors, I'm not sure how that should be handled; if we should force consistency across all values.

Dan McGrath

Posted 14 years ago

Reputation: 959

Question was closed 6 years ago

So I'm assuming the input is always a 4 character string? – None – 14 years ago

That is correct @Mike – Dan McGrath – 14 years ago

3You should include some correct input/output examples including "difficult" input like 0001, 0633, etc... I notice that many answers actually produce incorrect results. – MtnViewMark – 14 years ago

@SimpleCoder: I think a "smallest positive" implies clockwise angle. Counterclockwise would correspond to negative angles. "Smallest" probably means "least multiple of 2*pi". – hallvabo – 14 years ago

It appears that this wasn't originally code-golf. But now that it is, consider revising the accepted answer. – Adám – 9 years ago

1Oh boy, after 5 years my SO notification bar has been going crazy. What a surprising necro, haha. I'll check back in a few days to see if anyone can confirm the APL answer is correct (I'm traveling). I haven't been on this site for ages, but it would sure be nice to be able to mark golfs by language since this has since becoming golfing. – Dan McGrath – 9 years ago

You can download a free APL interpreter from dyalog.com.

– Adám – 9 years ago

Why do everybody golf, when it was not supposed to golf? ) – Nakilon – 14 years ago

1@Nakilon: Can't speak for anyone else, but in my case {1} I missed the tagging (need to establish new habits for this place), {2} golfing is why I came here, and {3} it's kind of simple for anything else, isn't it? – dmckee --- ex-moderator kitten – 14 years ago

A few of the example answers are incorrect and the question is poorly worded ("positive angle only" for instance). I've corrected the examples, clarified the answer, and provided some more examples to highlight possible errors. – None – 14 years ago

2The clockwise angle, or the smallest of the two? – Chris Laplante – 14 years ago

1@SimpleCoder: Smallest, as the question says. – Chris Jester-Young – 14 years ago

00:10 will be 0010 or 010? – Nakilon – 14 years ago

It will be 0010 in 24 hour time @Nakilon – Dan McGrath – 14 years ago

Answers

15

Haskell - 78 characters

q[h,i,m,n]=abs$((600*h+60*i-110*m-11*n-312)`mod`720)-360
c s=q$map fromEnum s

Note: My "unit of choice" is the "half-degree", of which there are 720 to the circle. With these units, the answer to the problem is always integral! :-)

Ex.:

> map c $ words "0000 0001 0010 0630 0633 2325 2345 2355 2359"
[0,11,110,30,3,335,165,55,11]
> map c $ words "0930 1845 0315 1742 2359"
[210,135,15,162,11]

MtnViewMark

Posted 14 years ago

Reputation: 4 779

Half-a-degree's. Nice. – dmckee --- ex-moderator kitten – 14 years ago

c s=q$map fromEnum s can be c=q.map fromEnum. ( ... )`mod`720 can be mod( ... )720. – Laikoni – 7 years ago

11

Golfscript, 42 bytes

2/~~\~60*+55*3600%.3600\-]{}$~;.10/'.'@10%

Outputs whole-a-degrees in float format.

aaaaaaaaaaaa

Posted 14 years ago

Reputation: 4 365

1+1 Great program! You can save a char by assigning 3600 to a variable and reusing that. – Cristian Lupascu – 12 years ago

@w0lf ah good trick. I dont know any golf script, but thats bound to save like 2-5 bytes. – Ashwin Gupta – 9 years ago

6

ES6, 52 50 bytes

t=>(t=(t-t.match`..`*40)*11%720,(t>360?720-t:t)/2)

Input string, output in degrees. If half degrees is acceptable, 46 bytes:

t=>(t=(t-t.match`..`*40)*11%720,t>360?720-t:t)

Edit: Saved 2 bytes by using a template string parameter to match.

Neil

Posted 14 years ago

Reputation: 95 035

6

TI-BASIC, 22 bytes

expr(Ans
sin⁻¹(sin(πfPart(11/6!(Ans-40int(sub(Ans

My unit is the "πth of a revolution", equal to 2 radians. The TI-83+ was introduced in 1996, making it much older than this challenge and thus eligible.

First we evaluate the string using expr(, then:

                                 sub(Ans   input/100. Don't ask why.
                             int(sub(Ans   Number of hours
                           40              Times 40
                       Ans-                Subtract from input. This converts to minutes.
                 11/6!(                    Multiply by 11/720 since 720/11 is the period.
           fPart(                          Take fractional part
sin⁻¹(sin(π                                Map [0,½] to [0,π/2] and [½,1] to [π/2,0].

All test cases have been verified.

lirtosiast

Posted 14 years ago

Reputation: 20 331

wait what!? sub( is a string manipulation function... Yeah, I'm asking :P – Conor O'Brien – 9 years ago

1sub( is a bit strange: it's the one only overloaded TI-BASIC command. When called with a number or list as its only argument, it calculates x/100, vectorized on lists. See here. – lirtosiast – 9 years ago

1@DanMcGrath I've revised my answer to take input as a string. If an integer is acceptable, I'll revert. – lirtosiast – 9 years ago

5

Perl, 58 characters

Perl is fun

perl -nlE "/(..)(..)/;$r=abs$1%12*30-5.5*$2;say+($r,360-$r)[$r>180]"

chinese perl goth

Posted 14 years ago

Reputation: 1 089

4

C99, 86 78 bytes

My units are twelfths of revolutions (so 3 corresponds to 90°)

#include<math.h>
float f(int t){return fabs(remainder((t+t%100/1.5)*.11,12));}

Equivalently, in C++14, for 76 bytes:

#include<cmath>
auto f(int t){return fabs(remainder((t+t%100/1.5)*.11,12));}

BSD and SVID platforms have remd as an alias for remainder (to save 5 more), but I'm sticking with standard C and C++.

Explanation

We convert sexagesimal seconds to centihours by adding t%100/1.5 (so 0030 becomes 0050 etc), and divide by 100 to get hours. Coincidence of hands occurs 11 times every 12 hours, so multiply by 11 and divide by 12; we take the remainder in the range [-6,+6], and return its absolute value.

Test program

#include <stdio.h>
#include <stdlib.h>
int main(int argc, char**argv)
{
    int i;
    for (i = 1;  i < argc;  ++i)
        printf("%4s: %f\n", argv[i], f(atoi(argv[i])));
    return 0;
}

Test output:

A minimum around 12:00:

1150: 1.833333
1151: 1.650000
1152: 1.466667
1153: 1.283333
1154: 1.100000
1155: 0.916667
1156: 0.733333
1157: 0.550000
1158: 0.366667
1159: 0.183333
1200: 0.000000
1201: 0.183333
1202: 0.366667
1203: 0.550000
1204: 0.733333
1205: 0.916667
1206: 1.100000
1207: 1.283333
1208: 1.466667
1209: 1.650000
1210: 1.833333

And a maximum around 6:00:

0555: 5.083333
0556: 5.266667
0557: 5.450000
0558: 5.633333
0559: 5.816667
0600: 6.000000
0601: 5.816667
0602: 5.633333
0603: 5.450000
0604: 5.266667
0605: 5.083333

Toby Speight

Posted 14 years ago

Reputation: 5 058

You can squeeze more bytes by declaring the function anonymous and generic, also returning via reference parameter saves bytes: https://codegolf.stackexchange.com/questions/137549/dropsort-it-like-its-hot/137854#137854

– Karl Napf – 7 years ago

4

Dyalog APL, 34 32 27 25 characters

Full program. Prompts for 4-character string from stdin. Prints radians to stdout.

¯2○2○○360÷⍨11×60⊥⍎¨↓2 2⍴⎕

Try it online!

The angle changes linearly with the time, going through 22×360° every 1440 minutes, or 5.5°/min.

Method:

  1. Take input: 

  2. Make into 2-by-2 table: 2 2⍴

  3. Split into rows: 

  4. Evaluate each: ⍎¨

  5. Convert to minutes: 60⊥

  6. Convert to degrees and then to radians (5.5t × π/180 = 11t × π/360): ○360÷⍨11×

  7. arccos cos to invert after π/2: ¯2○2○

Test cases can be verified by converting the result into degrees:

      angle←  {¯2○2○○360÷⍨11×60⊥⍎¨↓2 2⍴⍵}
      rads2degs←{180×⍵÷○1}

      rads2degs angle ¨ '0000' '0010' '0020' '0030' '0040' '0050' '0150' '0240' '0725' '1020' '1350' '1725'
0 55 110 165 140 85 115 160 72.5 170 115 12.5

Try it online!

Adám

Posted 14 years ago

Reputation: 37 779

3

Ruby 1.9.2p136 : 78 74

def a(t)m=t[2,2].to_f
180-((m*6-(m/60+t[0,2].to_f%12)*30).abs-180).abs
end

Sample output:

["0000", "0010", "0020", "0030", "0040", 
  "0050", "0150", "0240", "0725", "1020", 
  "1350", "1725"].each do |time|
  puts "#{time} = #{a(time)}"
end
# Output
0000 = 0.0
0010 = 55.0
0020 = 110.0
0030 = 165.0
0040 = 140.0
0050 = 85.0
0150 = 115.0
0240 = 160.0
0725 = 72.5
1020 = 170.0
1350 = 115.0
1725 = 12.5

Mike Bethany

Posted 14 years ago

Reputation:

1You output has the hour hand fixed on the hour marks rather than sweeping during the hour. Most answers have been assuming a uniform sweep for the hour hand. – dmckee --- ex-moderator kitten – 14 years ago

Yep, and it also doesn't work if the hour hand is at say 1 and the minute hand is at 11. I fell asleep before fixing it... – None – 14 years ago

Fixed and updated. – None – 14 years ago

3

Perl, 91 chars

#!perl -n
($h,$m)=/(..)(..)/;$h=$h%12+$m/60;$h=abs($h*30-$m*6);printf'%f
',$h>180?360-$h:$h

Chris Jester-Young

Posted 14 years ago

Reputation: 4 464

3

Perl, 61 characters:

sub f{$a=abs(int($_[0]/200)-($_[0]%60)/5);($a>6?12-$a:$a)*30}

Anon.

Posted 14 years ago

Reputation: 1 799

1Your answer is wrong: 1. It generates wrong results for 1059, 1058, etc. 2. 0020 should be 110 degrees, 0030 should be 165, 0040 should be 140, and 0050 should be 85. (The hour hand moves 30 degree every hour---thus, it moves half a degree every minute.) – Chris Jester-Young – 14 years ago

3

Python, 82 bytes

def a(t):
    o=abs(30*(int(t[:1])%12)-5.5*int(t[2:]));return o if o<=180 else 360-o

With some help from the python golfing question I've brought it down to 76:

def a(t):
    o=abs(30*(int(t[:1])%12)-5.5*int(t[2:]));return [o,360-o][o>180]

Juan

Posted 14 years ago

Reputation: 2 738

no need for a space itn return [. You should convert to a lambda function anyhow if you can (for golfing) – gnibbler – 14 years ago

3

Matlab/Octave, 56 bytes

An anonymous function accepting a string, output is in degrees.

@(i)180-abs(mod((i-48)*[600;60;10;1],720/11)-360/11)*5.5

flawr

Posted 14 years ago

Reputation: 40 560

2

Python, 106 bytes

Non-golf solution:

def angle_24hr(time_str):
    hour, minute = int(time_str[0:1]) % 12, int(time_str[2:3]) % 60
    angle_dist = lambda a, b: ((a + (180 - b)) % 360) - 180
    return angle_dist(((hour * 30) + (minute * 0.5)), minute * 6) * 10

In a more obscure/obfuscated form (admittedly, one of my first code golfs):

ad=lambda a,b:((a-b+180)%360)-180;x=int;ag=lambda t:10*ad((x(t[0:1])%12)*60+x(t[2:3]),(x(t[2:3]*12)%60)*6)

(what's the point of obfuscating Python?)

If it's necessary for the angles to be purely positive you can remove the -180 term.

Thomas O

Posted 14 years ago

Reputation: 3 044

1Depends on your clock. My clock only moves the hour hand on full hours. Since it wasn't specified in the question it wouldn't make much sense to do it the hard way would it? OK... I'll just admit it... I screwed up to... doh! – None – 14 years ago

Your answer is wrong: 0020 should be 110 degrees, 0030 should be 165, 0040 should be 140, and 0050 should be 85. (The hour hand moves 30 degree every hour---thus, it moves half a degree every minute.) – Chris Jester-Young – 14 years ago

@Chris, why 110 degrees for 0020? Am I missing something: hour hand is at 0, minute hand is at 20*6 = 120...? – Thomas O – 14 years ago

The hour hand is not at 0 when the minute hand is at 20. It's at one-third between 12 and 1. – Chris Jester-Young – 14 years ago

@Chris Of course, now it seems obvious to me. Back in a sec with fixed code. – Thomas O – 14 years ago

2

PHP, 80 Characters

<?=($i=$argv[1])&&($n=abs(($i[0].$i[1])%12*30-($i[2].$i[3])*5.5))>180?360-$n:$n;

Can be run from CLI php /script_name input

Explanation:

<?=                           // output result to console
    ($i = $argv[1]) && (      // $argv is an array containing CLI parameters (0: script name, 1: first parameter, etc.)
        $n = abs(             // absolute value to deal with negative numbers
            ($i[0] . $i[1])   // get hours - the first two characters from the input (0 and 1)
                % 12 * 30     // modulus 12 to deal with PM hours (13-23) multiplied by 360/12 = 30 degrees
            - ($i[2] . $i[3]) // get minutes - the subsequent characters from the input (2 and 3)
                * 5.5)        // multiply minutes by 5.5 (1 minute is 360/60 = 6 degrees
                              // and the hour hand moves every minute by 30/60 = 0.5 degrees which we subtract)
        ) > 180               // compare obtained result to 180
    ? 360 - $n                // if the result is greater subtract it from 360
    : $n;                     // if it's less - output as it is

Test cases (input output)

0000 0
0010 55
0155 87.5
0240 160
1234 173
2155 32.5
2222 179

patrick

Posted 14 years ago

Reputation: 31

2Have I missed something? This works correctly for all examples given in the question, so can't imagine why was downvoted. – manatwork – 9 years ago

1Welcome to Programming Puzzles & Code Golf! Sorry your first post got downvoted; I see no reason why it should be. Though if you could add some explanation of the code, that would be nice. :) – Alex A. – 9 years ago

Thanks guys. Added code explanation. Maybe someone's angry that we've resurrected a five year old thread :) – patrick – 9 years ago

2

Mathematica

Grid@Prepend[
Table[{Row[{Quotient[x, 60] /. {0 -> 12}, ":", If[Mod[x, 60] < 10, "0", ""], Mod[x, 60]}],
x, N[x/2, 3], Mod[6 x, 360], 
IntegerPart[Min[Abs[x/2 - Mod[6 x, 360]], 360 - Abs[x/2 - Mod[6 x, 360]]]]}, 
{x, 0, 12*60}], {"time", "elapsed min", "hourhand deg", "min deg", "diff deg"}]

Partial output in table

table

Graphs

Plot[{ x/2, Mod[6 x, 360], Min[Abs[x/2 - Mod[6 x, 360]], 360 - Abs[x/2 - Mod[6 x, 360]]]}, {x, 0, 12*60},PlotStyle -> {Green, Blue, {Thick, Red}},AxesLabel -> {"time (hs)", "degrees"},GridLinesStyle -> Directive[Dotted, Gray],Ticks -> {Table[{60 k, k}, {k, 0, 12}], Table[30 k, {k, 0, 12}]},GridLines -> {Table[60 k, {k, 0, 12}], None}]

The green line shows the angle of the hour hand, as measured in degrees from 12 o'clock, clockwise. The blue line shows the corresponding angle for the minute hand. The red curve shows the difference between the minute and hour hands in degrees; it always uses the interior angle.

graphs

DavidC

Posted 14 years ago

Reputation: 24 524

It does not seem like an attempt to golf the code has been made, which makes the answer in its current form invalid.

– Laikoni – 7 years ago

1

C# (.NET Core), 87 bytes

t=>{var i=int.Parse(t);double d=i/100%12*30-i%100*5.5,r=d<0?-d:d;return r>180?360-r:r;}

Try it online!

I'm sure there are possible improvements that I have missed.

DeGolfed

t=>{
    var i = int.Parse(t);
    // The hour angles minus the minute angles
    double d = i / 100 % 12 * 30 -
               i % 100 * 5.5,
    // account for this possibly being a negative angle
           r = d < 0? -d : d;

    // Get the smaller of the two possible rotational angles
    return r > 180? 360-r : r;
}

Ayb4btu

Posted 14 years ago

Reputation: 541

1

c99 -- 204 necessary characters (keeps getting worse as I fix bugs)

#include <stdio.h>
#include <stdlib.h>
#include <math.h>
int main(){char b[5]={0};fgets(b,5,stdin);int a,h,m=atoi(b+2);b[2]=0;
h=(atoi(b)*60+m)%720;m*=12;a=abs((h-m)%720);a=a>360?720-a:a;printf("%i\n",a);}

Discussion:

The problem turns out to be harder than it looks. The critical issue is what is meant by "smallest positive angle". I've interpreted that the mean a value between [0,180] degrees inclusive (because the problem does not specify which hand to start from when measuring).

To validate this behavior look for places when the hands pass the straight-apart position (such as around 00:33-00:35), and places where they cross-over as around 06:33.

I've also chosen to have a steadily sweeping hour hand, as most modern clocks seem to use that method.

I've adopted MtnViewMark clever trick of using half-degrees as the base unit.

I've suffered the usual problem with c: the preprocessor commands to get the libraries eat up a lot of characters.

Readable and commented:

#include <stdio.h>
#include <stdlib.h>
#include <math.h>
int main(){
  char b[5]={0};
  fgets(b,5,stdin); /* assumes single byte charaters */
/*   printf("'%s'\n",b); */
  int a,h,m=atoi(b+2); /* minutes */
  b[2]=0;
  h=(atoi(b)*60+m)%720;  /* hour had position in hald-degrees */
  m*=12;                 /* minute hand position in half degrees */
/*   printf("%3i\t%3i\n",h,m); */
/*   printf("%i\n", h-m ); */
/*   printf("%i\n",(h-m)%720 ); */
  a=abs((h-m)%720);
/*   printf("%i\n",   a ); */
  a=a>360?720-a:a;
  printf("%i\n",a);
}

Validation:

$gcc -c99 golf_clock_angle.c
$wc golf_clock_angle.c
  5  11 206 golf_clock_angle.c
$!for
for t in $(cat clock_test_times.txt); do echo $t $(echo $t|./a.out); done
0000 0
0001 11
0002 22
0010 110
0015 165
0030 330
0033 357
0034 346
0035 335
0045 225
0630 30
0633 3
0634 14
2324 324
2325 335
2355 55
2359 11

dmckee --- ex-moderator kitten

Posted 14 years ago

Reputation: 2 726

Says "Angles are to be returned in the unit of your choice"... ;-) – MtnViewMark – 14 years ago

@MntViewMark: Yep. But I'll bet Dan was thinking "degrees or radians" when he wrote that. – dmckee --- ex-moderator kitten – 14 years ago

Your answers are way off. For instance at 0010 the minute hand will be at 60 degrees and the hour hand will be at 5 degrees. There are 55 degrees between them. In fact a lot of your angles look doubled. – None – 14 years ago

@Mike: Note the units. I've adopted MntViewMark's convention of expressing answers in half-degrees. – dmckee --- ex-moderator kitten – 14 years ago

Ah, seems like cheating to me... let me see if I can abuse it too. ;) – None – 14 years ago

1

C++, 175 174 166 156 Characters

#include <iostream>
#include <cmath>
int main(){int m,h;std::cin>>h;m=h%100;h=(h-m)/100;h=h>11?h=h-12:h;h=std::abs(h*60-m*11);std::cout<<std::min(720-h,h);}

Using "half degree's" as my unit of choice :D

Try it Online!

jac4e

Posted 14 years ago

Reputation: 11

1

JavaScript (ES6), 75 bytes

x=>Math.min(x=((x=x.match(/\d\d/g))[0]*60+x[1]*1)*5.5%360,360-x).toFixed(1)

This question needed a JavaScript solution.

Mwr247

Posted 14 years ago

Reputation: 3 494

0

SmileBASIC, 60 bytes

INPUT T
A=ABS(T DIV 100*60-T MOD 100*11)?A/2+(360-A)*(A>360)

12Me21

Posted 14 years ago

Reputation: 6 110

0

05AB1E, 23 bytes

2ôć12%30*s11;*αD360α)˜ß

Outputs degrees like the challenge description.

Port of @Juan's Python answer.

Try it online or verify all test cases.

Explanation:

2ô                  # Split the (implicit) input in pieces of 2
                    #  i.e. "0150" → ['01','50']
  ć                 # Head extracted
                    #  i.e. ['01','50'] → ['50'] and '01' are pushed to the stack
   12%              # Take the hours modulo 12
      30*           # Multiplied by 30
                    #  i.e. '01' → 30
  s                 # Swap so the minutes are now at the top of the stack
   11;*             # And multiple it by 5.5
                    #  i.e. ['50'] → [275.0]
       α            # Calculate the absolute difference between the two values
                    #  30 and [275.0] → [245.0]
        D           # Duplicate this value
         360α       # Calculate the absolute difference between this value and 360
                    #  i.e. [245.0] → [115.0]
             )      # Wrap the entire stack to a list
                    #  i.e. [245.0] and [115.0] → [[245.0],[115.0]]
              ˜     # Flatten this list (necessary due to the head extracted)
                    #  i.e. [[245.0],[115.0]] → [245.0,115.0]
               ß    # And take the smallest value of the two (output implicitly)
                    #  i.e. [245.0,115.0] → 115.0

Kevin Cruijssen

Posted 14 years ago

Reputation: 67 575