12
\$\begingroup\$

This a simple question.

The start day is a Saturday and let the input be a non-negative number x.

The output should be the number of weekdays (Mon-Fri) in the next x days inclusive.

For example, if x = 3 then the output should be 2. For x from 0 onwards the output should be:

0,0,1,2,3,4,5,5,5,6,7,8,9,10,10,10,11,...

—-—

Now I am regretting not having asked the question for a user specified day of the week instead of just Saturday. It’s too late to change the question now and a new question would probably be marked as a duplicate. If anyone wanted to add an answer for this extension, I would love to see it.

\$\endgroup\$
1
  • 6
    \$\begingroup\$ I found the title on this really confusing. I assumed it meant "how many weekdays until Saturday" which should never exceed five. But actually you're asking something completely different. I suggest revising the title to "how many weekdays" \$\endgroup\$ Jun 28, 2020 at 13:29

24 Answers 24

16
\$\begingroup\$

Python 2, 18 bytes

lambda x:x*6/7-x/7

Try it online!

Found by brute-forcing. x*6/7 counts non-Sundays, and -x/7 subtracts the number of Saturdays.

all          x       0  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16 ...

all - Sun  = x*6/7   0  0  1  2  3  4  5  6  6  7  8  9 10 11 12 12 13 ...
Sat        = x/7     0  0  0  0  0  0  0  1  1  1  1  1  1  1  2  2  2 ...
all - Sun - Sat      0  0  1  2  3  4  5  5  5  6  7  8  9 10 10 10 11 ...

Brute-forcing suggests that this is the unique arithmetical solution of this length or shorter, subject to some limitations like not using parens, using only single-digit constants, and not having too-large intermediate results.


19 bytes

lambda x:x-x/7+-x/7

Try it online!

Found by brute-forcing. But, it has a nice interpretation. x counts all x days. Then -x/7 subtracts the number of Sundays in those x days, and +-x/7 subtracts the number of Saturdays. Note that there's a difference in Python between subtracting x/7 and adding -x/7 aka (-x)/7, because floor-div is not symmetric around zero since it always round down.

all =   x        0  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16 ... 
Sun =   x/7      0  0  0  0  0  0  0  1  1  1  1  1  1  1  2  2  2 ...
Sat = -(-x/7)    0  1  1  1  1  1  1  1  2  2  2  2  2  2  2  3  3 ...

all - Sun - Sat  0  0  1  2  3  4  5  5  5  6  7  8  9 10 10 10 11 ...

20 bytes

lambda x:x*5/7+x%7/4

Try it online!

I found this by hand, noting that f(x) increases asymptotically with slope 5/7 and seeing that the difference to x*5/7 (with floor-division) has a nice period-7 form.

\$\endgroup\$
9
  • \$\begingroup\$ What does +- do? \$\endgroup\$
    – user9207
    Jun 28, 2020 at 7:17
  • 1
    \$\begingroup\$ @Anush The +-x/7 adds the term -x/7 AKA (-x)/7, which is different from the earlier term -x/7 which subtracts x/7, since Python's mod isn't symmetric around zero. \$\endgroup\$
    – xnor
    Jun 28, 2020 at 7:19
  • \$\begingroup\$ I wonder what you can do in Python 3. \$\endgroup\$
    – user9207
    Jun 28, 2020 at 7:27
  • \$\begingroup\$ @Anush That's an interesting question. Since the / will need to be //, it might be that something with % for mod becomes better. I'll see what the brute-forcing gives. \$\endgroup\$
    – xnor
    Jun 28, 2020 at 7:29
  • 1
    \$\begingroup\$ @Anush Maybe? I don't see an obvious extension, but there's probably some way to incorporate an offset corresponding to the starting day. \$\endgroup\$
    – xnor
    Jul 1, 2020 at 9:22
8
\$\begingroup\$

05AB1E, 8 6 bytes

Ý7%1›O

Try it online!

Very similar to the APL answer

Explained

Ý    | Generate a list between 0 and input 
7%   | Mod each number by 7
1›   | Determine if each number is greater than 1
O    | Summate the list and output it
\$\endgroup\$
8
\$\begingroup\$

APL (Dyalog Unicode), 7 bytes

+/2≤7|⍳

Try it online!

1-based range is a big win here.

How it works

+/2≤7|⍳
      ⍳  ⍝ 1-based range
    7|   ⍝ modulo 7; 1 2 3 4 5 6 0 ...
  2≤     ⍝ is at least 2; 0 1 1 1 1 1 0 ...
+/       ⍝ sum the booleans

For the bonus question (let the user provide the day of the week to start):

APL (Dyalog Unicode), 11 bytes

+/⎕⍴⎕⌽7↑5⍴1

Try it online!

We don't need any fancy arithmetic. Just create a bit vector, rotate it to match the requested day of week to start with, cycle it and count ones (i.e. sum).

Accepts Sun, Mon, ..., Sat as the number 0, 1, ..., 6 as the first input, and the number of days as the second (both from stdin). (It actually works for any integers (for the first input) and gives the result as if it was modulo 7.)

How it works

+/⎕⍴⎕⌽7↑5⍴1
      7↑5⍴1  ⍝ 1 repeated 5 times and then overtaken to length 7
             ⍝ i.e. 1 1 1 1 1 0 0
    ⎕⌽  ⍝ Take the starting weekday and rotate ^ that many units to the left
  ⎕⍴    ⍝ Take the number of days and cycle ^ to that length
+/      ⍝ Sum
\$\endgroup\$
1
  • \$\begingroup\$ Thank you for the bonus answer! \$\endgroup\$
    – user9207
    Jun 29, 2020 at 5:50
4
\$\begingroup\$

JavaScript (ES6), 16 bytes

n=>n*20/7+n%7>>2

Try it online!

How?

The expression \$\lfloor 5n/7\rfloor\$ gives the correct answer when \$n\bmod 7\$ is less than or equal to \$3\$ but is off by \$1\$ otherwise.

 n           | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16
-------------+---+---+---+---+---+---+---+---+---+---+----+----+----+----+----+----+----
 floor(5n/7) | 0 | 0 | 1 | 2 | 2 | 3 | 4 | 5 | 5 | 6 |  7 |  7 |  8 |  9 | 10 | 10 | 11
 expected    | 0 | 0 | 1 | 2 | 3 | 4 | 5 | 5 | 5 | 6 |  7 |  8 |  9 | 10 | 10 | 10 | 11
 difference  | 0 | 0 | 0 | 0 | 1 | 1 | 1 | 0 | 0 | 0 |  0 |  1 |  1 |  1 |  0 |  0 |  0
 n mod 7     | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 0 | 1 | 2 |  3 |  4 |  5 |  6 |  0 |  1 |  2

This can be adjusted with:

$$f(n)= \left\lfloor\frac{5n}{7}\right\rfloor+\left\lfloor\frac{n\bmod 7}{4}\right\rfloor$$

which may also be expressed as:

$$f(n)= \left\lfloor\frac{20n/7+(n\bmod 7)}{4}\right\rfloor$$


JavaScript (Node.js), 15 bytes

In order to use @xnor's formula without adding explicit floor operations, we have to work with BigInts. So this version expects a BigInt as input.

n=>n*6n/7n-n/7n

Try it online!

\$\endgroup\$
10
  • \$\begingroup\$ Does 20/7*n run the risk of a floating-point rounding error in a way n*20/7 would not? \$\endgroup\$
    – Neil
    Jun 28, 2020 at 10:22
  • \$\begingroup\$ @Neil I'm almost certain it's safe in this case. But since you're right in the general case, I've updated it anyway. \$\endgroup\$
    – Arnauld
    Jun 28, 2020 at 10:35
  • \$\begingroup\$ I really like this answer because I can read it and it comes with math. More languages have integer division than I had expected! \$\endgroup\$
    – user9207
    Jun 29, 2020 at 6:09
  • \$\begingroup\$ @Anush Just to clarify, JS doesn't have integer division (which is why I use a right-shift instead) unless we work with BigInts. I've added a port of xnor's answer to illustrate that. \$\endgroup\$
    – Arnauld
    Jun 29, 2020 at 7:04
  • \$\begingroup\$ How come 20/7 doesn't return a float in that case? Are you assuming BigInts there too? \$\endgroup\$
    – user9207
    Jun 29, 2020 at 8:28
3
\$\begingroup\$

Japt, 7 bytes

Port of Bubbler's APL solution so be sure to +1 them, too.

õu7 x¨2

Try it - Includes all test cases

\$\endgroup\$
3
\$\begingroup\$

bc, 29 bytes

define f(n){return n*6/7-n/7}

Try it online!

\$\endgroup\$
2
\$\begingroup\$

Jelly, 6 bytes

R%7>1S

Try it online!

Interestingly equal-length in all regards to Lyxal's 05AB1E answer, so I've copy-pasted the explanation, swapping out the commands.

R    | Generate a list between 0 and input 
%7   | Mod each number by 7
>1   | Determine if each number is greater than 1
S    | Summate the list and output it
\$\endgroup\$
1
  • 3
    \$\begingroup\$ An all-ASCII Jelly answer, isn't that world first? :P \$\endgroup\$
    – Sok
    Jun 29, 2020 at 15:17
2
\$\begingroup\$

C (gcc), 18 bytes

f(n){n=n*6/7-n/7;}

Try it online!

Port of xnor's formula from his Python 2 answer.

\$\endgroup\$
2
\$\begingroup\$

Java, 12 bytes

x->x*6/7-x/7
\$\endgroup\$
2
\$\begingroup\$

perl -Minteger -lp, 14 bytes

$_=$_*6/7-$_/7

Try it online!

Uses the same algorithm as the Python 2 solution from @xnor. The -Minteger switch makes perl use integer division.

\$\endgroup\$
0
2
\$\begingroup\$

x86-16 machine code, 16 bytes

33 DB       XOR  BX, BX         ; clear BX sum 
        MLOOP: 
E3 0B       JCXZ DONE           ; handle x = 0 
8A C1       MOV  AL, CL         ; loop counter to AL
D4 07       AAM  7              ; AL = AL mod 7 
3C 01       CMP  AL, 1          ; AL <= 1 ? 
7E 01       JLE  IS_WEEKEND     ; if so, is a weekend
43          INC  BX             ; otherwise increment count 
        IS_WEEKEND: 
E2 F3       LOOP MLOOP          ; loop until 0
        DONE: 
C3          RET                 ; return to caller

Callable function, input in CL (unsigned byte) output to BX.

enter image description here

Or 22 bytes to operate on 16 bit unsigned WORD in CX:

33 DB       XOR  BX, BX         ; clear BX sum 
        MLOOP: 
E3 11       JCXZ DONE           ; handle x = 0 
8B C1       MOV  AX, CX
33 D2       XOR  DX, DX         ; clear DX (high word of quotient)
BF 0007     MOV  DI, 7          ; set up WORD divisor
F7 F7       DIV  DI             ; DX = DX:AX mod DI
80 FA 01    CMP  DL, 1          ; DL <= 1 ?
7E 01       JLE  IS_WEEKEND     ; if so, is a weekend 
43          INC  BX             ; otherwise increment count 
        IS_WEEKEND: 
E2 ED       LOOP MLOOP 
        DONE: 
C3          RET                 ; return to caller
\$\endgroup\$
2
\$\begingroup\$

Julia, 143 Bytes

function weekdays(days)
    r = mod(days, 7)
    if r <= 2 r=0
    else r -= 2
    end
    wd::Int64 = floor(days/7)
    return(5 * wd + r)
end

Try it online!

To use a custom start date, I add an offset argument, and days += offset at the start of the function

\$\endgroup\$
2
  • 1
    \$\begingroup\$ Golfed, 89 bytes \$\endgroup\$
    – lyxal
    Jul 5, 2020 at 4:40
  • 2
    \$\begingroup\$ Welcome to the site! These tips for golfing in Julia might be helpful. Also note that you should avoid using spaces (where possible) to minimise your byte count. \$\endgroup\$
    – Dingus
    Jul 5, 2020 at 10:04
1
\$\begingroup\$

Retina 0.8.2, 22 bytes

.+
$*
.(.{0,5}).?
$1
.

Try it online! Link includes test cases. Explanation:

.+
$*

Convert to unary.

.(.{0,5}).?

For each week, match Sunday, then up to five weekdays, then optionally match Saturday.

$1

Keep just the weekdays.

.

Count the resulting weekdays.

\$\endgroup\$
1
\$\begingroup\$

Charcoal, 10 bytes

IΣ…⪫00×⁵1N

Try it online! Link is to verbose version of code. This is actually 3 bytes shorter than trying to calculate the result arithmetically. Explanation:

        1   Literal string `1`
      ×⁵    Repeated 5 times i.e. `11111`
    00      Literal string `00`
   ⪫        Join its characters giving `0111110`
  …      N  Cyclically extend to the input number of days
 Σ          Sum the digits
I           Cast to string
            Implicitly print
\$\endgroup\$
1
\$\begingroup\$

Pyth, 8 bytes

lf<1%T7S

Try it online!

Port of Bubbler's APL solution.

Explanation

lf<1%T7S
l         : length of
 f        : filter on
       S  : 1-based range to input
  <1%T7   : where mod 7 is greater than 1
\$\endgroup\$
1
\$\begingroup\$

AWK, 29 bytes

{print int($0*6/7)-int($0/7)}

Try it online!

Port of @xnor's Python 2 answer.

\$\endgroup\$
1
  • \$\begingroup\$ Shaping the code like this will save 4 bytes: $0=int($0*6/7)-int($0/7)e \$\endgroup\$ Jan 12, 2021 at 22:07
1
\$\begingroup\$

Befunge-93, 12 bytes

&:6*7/\7/-.@

Try it online!

Another port of xnor's algorithm.

\$\endgroup\$
1
\$\begingroup\$

Pyth, 7 bytes

sm<1%d7

Try it online!

Port of Lyxal's 05AB1E answer.

sm<1%d7   
 m        For each number from 0-input:
    %d7     Mod 7
  <1        Greater than 1
s         Take the sum, implicit print
\$\endgroup\$
1
  • \$\begingroup\$ Also 7 bytes: t-Qy/Q7 \$\endgroup\$
    – Scott
    Feb 15, 2021 at 21:48
1
\$\begingroup\$

Io, 44 bytes

It seems like ranging is too costly here.

f :=method(x,if(x>0,if(x%7>1,1,0)+f(x-1),0))

Try it online!

Io, 46 bytes

method(x,Range 0 to(x)map(i,if(i%7>1,1,0))sum)

Try it online!

\$\endgroup\$
1
\$\begingroup\$

brainfuck, 142 bytes

(Due to number-wrapping problems) The maximum supported input is 255.

>,[[>+>+<<-]>[-<+>]<->>>+++++++<[>->+<[>]>[<+>-]<<[<]>-]>[-]>>+<[<<<+>>>>[-<<<<[-]>+>>>]<<<<[->>+<<]>[->>>+<<<]>>>-<-]>[-]<<[-<<<<+>>>>]<<<]<.

Try it online!

If you are not sure whether this output is correct, try this link.

Explanation

>,

Read input

[

While the input is nonzero:

[>+>+<<-]>[-<+>]

>x 0 0 -> x 0 >x

<->>>+++++++<[>->+<[>]>[<+>-]<<[<]>-]>[-]

Modulo by 7

>>+<[<<<+>>>>[-<<<<[-]>+>>>]<<<<[->>+<<]>[->>>+<<<]>>>-<-]>[-]<<

Check if this number is greater than 1

[-<<<<+>>>>]<<<

Add it to the accumulator (at the first item of the tape)

]

End while

<.

Move to the accumulator, print the value.

\$\endgroup\$
0
\$\begingroup\$

Keg, 10 bytes

0&1ɧ⑷7%1>⑼

Try it online!

Total not a port of Lyxal's my 05AB1E answer... (spoiler, it is). ;P

Explained

0&1ɧ⑷7%1>⑼
0&              # Store 0 in the register, as this will be used to keep track of the number of weekdays
  1ɧ            # Create a range between 1 and the implicit input
    ⑷           # Map the following to each item in the stack:
      7%1>⑼     # Increment the register by whether or not ((item % 7) > 1)
\$\endgroup\$
0
\$\begingroup\$

Vyxal, s, 5 bytes

ʀ7%1>

Try it Online!

Another port of my 05AB1E answer

\$\endgroup\$
0
\$\begingroup\$

x86-16 machine code, 18 16 bytes (No Loop):

Bytecode: "\xD4\x07\x88\xC1\xC1\xE8\x08\x6B\xC0\x05\x49\x78\x02\x01\xC8\xC3"

0:  d4 07                   aam    0x7          ; eax contains n, with aam 0x7 -> al = n % 7 and ah = n / 7 
2:  88 c1                   mov    cl,al        ; keep result of n%7 in ecx
4:  c1 e8 08                shr    ax,0x8       ; by shifting 8 times ax, ax=al=n/7;
7:  6b c0 05                imul   ax,ax,0x5    ; we multiply by 5
a:  49                      dec    ecx          ; ecx = ecx - 1 -> give 65535 if n was power of 7
b:  78 02                   js     11 <end>     ; if it happened we don't care about the remainder so we can just return n/7*5, the Signed Flag will be set so we can jump 2 bytes forward.
d:  01 c8                   add    eax,ecx      ; if not then we add (n%7)-1 to n/7*5
00000011 <end>:
f:  c3                      ret

obtained from assembling thanks to objdump -d -mi8086 dayofweek.s

global dayofweek

bits 16

section .text

dayofweek:
    aam  7
    mov  cl, al
    shr  ax, 8
    imul ax,5
    dec  ecx
    js   end
    add  eax,ecx
end:
    ret

Test: main.c

int main() {
    for (short i = 0; i < 50; i++)
        printf("%2d %2d\n", dayofweek(i), (i*20/7+i%7)/4);
    return 0;
}

output:

0  0
0  0
1  1
2  2
3  3
...
33 33
34 34
35 35
35 35

It is not as short as @640KB (16 bytes) but I believe it is still an interesting answer as it provides a better performance (no loop)

edit: Thanks to Peter -2 bits

NB (Peter): Do note that aam only divides AL, not AX, so you might as well declare the arg in C as uint8_t, as well as specifying the gcc -mregparm=3 calling convention to put it in the reg you want.

\$\endgroup\$
8
  • 1
    \$\begingroup\$ You say this is supposed to be 16-bit code, and you even used bits 16, but you have a 66 operand-size prefix on instructions using 16-bit registers but not on instructions like add eax, ecx. That's backwards; that machine code is what you'd get if you assembled for 32-bit mode. Did you take this machine code from before you added bits 16 to the source? \$\endgroup\$ Feb 21, 2021 at 6:09
  • \$\begingroup\$ Good point, I got the bytecodes from defuse.ca/online-x86-assembler.htm#disassembly , how could I get the 16 bits version in local ? \$\endgroup\$ Feb 21, 2021 at 6:13
  • \$\begingroup\$ Just use nasm -fbin -l/dev/stdout to get a listing, or objdump -d -mi8086 to disassemble as 16-bit if you have machine code in an ELF object. And IDK what good gcc-multilib would be for 16-bit code, I guess you actually built that as 32-bit so you could call from C easily. I was going to say I guess you disassembled that by mistake, but yeah, using a 32-bit-mode online assembler would have the same problem. \$\endgroup\$ Feb 21, 2021 at 6:16
  • \$\begingroup\$ Also obviously use 16-bit (or 8-bit) operand-size as much as possible to save bytes, with your return value only in AX. (So the C return type is unsigned short). Or just do this in 32-bit code; unless 16-bit lets you avoid high garbage in EAX outside what aam deals with. Also, you seem to be using dec ecx after only writing CL, so the sign flag will depend on garbage left in high bytes of ECX. (And you haven't documented a calling convention, but it looks like gcc -mregparm=3 so first arg in EAX). \$\endgroup\$ Feb 21, 2021 at 6:22
  • \$\begingroup\$ xchg al, ah / imul ax, 5 might work to leave a valid result in the low byte of EAX (aka AL). The low bits of a multiply don't depend on the high bits of the inputs (think of it as adding at various left shifts, and adding only propagates carry from low to high). Or perhaps xchg ax,cx (1 byte) / mov al, ch (2B) / imul ax, 5 (3B) to also replace the mov cl,al. As long as your result fits in 1 byte, you're fine, but that might not be justified. So perhaps movzx ax, ch (3B) to still allow xchg but avoid the immediate shift. That'd allow 32-bit mode. \$\endgroup\$ Feb 21, 2021 at 6:24
0
\$\begingroup\$

PowerShell, 42 bytes

function x($y){[math]::floor($y*6/7-$y/7)}

Try it online!

Fork of Python 2 answer

\$\endgroup\$
1
  • \$\begingroup\$ Wasif, $y*6/7-$y/7 = $y*5/7 :) Try it online! \$\endgroup\$
    – mazzy
    Feb 22, 2021 at 5:36

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.