Additional facts!

17

1

In mathematics, the factorial, shortened "fact" of a non-negative integer n, denoted by n!, is the product of all positive integers less than or equal to n. For example, 5! is 1 * 2 * 3 * 4 * 5 = 120

The factorial of 0 is 1, according to the convention for an empty product.


These are the regular facts we are used to. Let's add some alternatives:

  1. The factorial (defined above)
  2. The double factorial: n!! = 1 + 2 + ... + n
  3. The triple factorial: n!!! = 1 - (2 - (3 - ( ... - n)))...)
  4. The quadruple factorial: n!!!! = 1 / (2 / (3 ... / n)))...). Note: This is floating point division, not integer division.

Challenge

Take a non-negative integer input n, directly followed by between 1 and 4 exclamation marks. The input will look (exactly) like this: 0!, 5!!, 132!!! or 4!!!!. In this challenge, you may not assume a flexible input format, sorry.

Output

The output should be the result, on any convenient format. The result of the quadruple factorial must have at least 2 digits after the decimal point, except for 0!!!! = 0.

Test cases:

0! = 1
1! = 1
2! = 2
3! = 6
4! = 24
5! = 120
6! = 720
7! = 5040
8! = 40320
9! = 362880
10! = 3628800
---
0!! = 0
1!! = 1
2!! = 3
3!! = 6
4!! = 10
5!! = 15
6!! = 21
7!! = 28
8!! = 36
9!! = 45
10!! = 55
---
0!!! = 0
1!!! = 1
2!!! = -1
3!!! = 2
4!!! = -2
5!!! = 3
6!!! = -3
7!!! = 4
8!!! = -4
9!!! = 5
10!!! = -5
---
0!!!! = 0
1!!!! = 1
2!!!! = 0.5
3!!!! = 1.5
4!!!! = 0.375
5!!!! = 1.875
6!!!! = 0.3125
7!!!! = 2.1875
8!!!! = 0.27344
9!!!! = 2.4609
10!!!! = 0.24609

The shortest solution in each language wins.

Stewie Griffin

Posted 2017-08-03T07:07:03.657

Reputation: 43 471

2Can the quadruple factorial also be rational division? – Martin Ender – 2017-08-03T07:12:05.490

@MartinEnder I guess. – Stewie Griffin – 2017-08-03T07:22:31.610

6"The double factorial" definition's a fit off... – Erik the Outgolfer – 2017-08-03T09:11:14.643

By "Take a non-negative input" do you mean "Take a non-negative integer input"? – Erik the Outgolfer – 2017-08-03T09:31:34.610

4@Erik, it's an alternative double fact ;-) – Stewie Griffin – 2017-08-03T09:39:36.803

1@StewieGriffin BTW it's a little bit sneaky that 0! -> 1. – Erik the Outgolfer – 2017-08-03T09:48:19.360

@EriktheOutgolfer It's surprising to some folks sometimes, but it's standard, to keep the formula n!*(n+1)=(n+1)! true even for n=0. Also, in other places in math, the product of an empty set is usually considered to be 1. – aschepler – 2017-08-03T11:23:38.647

@aschepler Well, as I read this challenge, I first supposed that for 0! it wanted me to reduce the empty list by * which is different from the empty product in some languages. – Erik the Outgolfer – 2017-08-03T11:26:32.777

5Title should be *Alternative Facts* – Digital Trauma – 2017-08-03T16:49:32.133

@DigitalTrauma that was actually the original title, but I edited because it was kind of political, and there's always someone who dislikes such references. – Stewie Griffin – 2017-08-03T18:47:15.447

Shouldn't the double factorial be defined as n!! = n * (n - 2) * (n - 4) * ...?

– tsh – 2017-08-04T06:12:27.877

Answers

7

JavaScript (ES6), 88 bytes

s=>eval(([a,b]=s.split(/\b/),g=k=>+a?k-a?k+'_*+-/'[b.length]+`(${g(k+1)})`:k:+!b[1])(1))

Test cases

let f =

s=>eval(([a,b]=s.split(/\b/),g=k=>+a?k-a?k+'_*+-/'[b.length]+`(${g(k+1)})`:k:+!b[1])(1))

for(o = '!'; o <= '!!!!'; o += '!') {
  for(n = 0; n <= 10; n++) {
    console.log(n + o + ' = ' + f(n + o));
  }
}

Formatted and commented

s =>                                // given the input string s,
  eval(                             // evaluate as JS code:
    ( [a, b] = s.split(/\b/),       //   a = integer (as string) / b = '!' string
      g = k =>                      //   g = recursive function taking k as input
        +a ?                        //     if a is not zero:
          k - a ?                   //       if k is not equal to a:
            k + '_*+-/'[b.length] + //         append k and the operation symbol
            `(${g(k + 1)})`         //         append the result of a recursive call
          :                         //       else:
            k                       //         just append k and stop recursion
        :                           //     else:
          +!b[1]                    //       return 1 for multiplication / 0 otherwise
    )(1)                            //   initial call to g() with k = 1
  )                                 // end of eval()

Arnauld

Posted 2017-08-03T07:07:03.657

Reputation: 111 334

7

Husk, 15 bytes

§!ëΠΣF-F/#'!oṫi

Try it online!

Explanation

Indexing into a list of functions: the joys of using a functional language.

§!ëΠΣF-F/#'!oṫi  Implicit input, say x = "6!!!"
              i  Convert to integer (parses the leading sequence of digits): 6
            oṫ   Descending range to 1: y = [6,5,4,3,2,1]
  ë              Four-element list containing the functions
   Π             product,
    Σ            sum,
     F-          left fold with subtraction (gives 0 for empty list), and
       F/        left fold with division (gives 0 for empty list).
 !               1-based index into this list with
         #'!     count of !-characters in input: gives F-
§                Apply to y and print implicitly: -3

I use a descending range and left folds, since - and / take their arguments in reverse order in Husk.

Zgarb

Posted 2017-08-03T07:07:03.657

Reputation: 39 083

Indexing into a list of functions is woah... – Erik the Outgolfer – 2017-08-03T12:08:35.153

I was thinking of Haskell, and then I see this... Truly seems to be the right tool for the job. +1 – alleks – 2017-08-04T03:40:29.267

This is what Husk was made for :D – Leo – 2017-08-05T19:48:26.160

6

C# (.NET Core), 134 130 128 bytes

s=>{double e=s.Split('!').Length,n=int.Parse(s.Trim('!')),i=n,r=n;for(;--i>0;)r=e>4?i/r:e>3?i-r:e>2?i+r:i*r;return n<1&e<3?1:r;}

Try it online!

The best part of code golfing are the things you learn while trying to solve the challenges. In this one I have learnt that in C# you can trim other characters besides whitespaces from strings.

  • 4 bytes saved thanks to LiefdeWen!
  • 2 bytes saved because I do not need to substract 1 to s.Split('!').Length, just fix the limits in e>4?i/r:e>3?i-r:e>2?i+r:i*r and n<1&e<3?1:r.

Charlie

Posted 2017-08-03T07:07:03.657

Reputation: 11 448

1You can make e n and i also double to avoid declaring it for r to save 4 bytes. – LiefdeWen – 2017-08-03T10:09:25.057

1@LiefdeWen Or float to save another byte. – Kevin Cruijssen – 2017-08-03T13:09:39.340

4

Perl 5, 62 bytes

61 bytes code + 1 for -p.

$_=/^0!$/+eval join(qw{| *( +( -( /(}[s/!//g],1..$_).")"x--$_

Thanks to @G B for pointing out a miss on my part!

Try it online! (this uses -l for readability)

Dom Hastings

Posted 2017-08-03T07:07:03.657

Reputation: 16 415

40! should be 1 not 0 – G B – 2017-08-03T09:39:34.437

@GB Well that doesn't make any sense... Fixed for +5! – Dom Hastings – 2017-08-03T12:07:01.937

4

Python3, 124 130 121 119 bytes

At this point, I believe that recursion is the key to further byte saving.

s=input()
l=s.count('!')
v=int(s[:-l])+1
print(eval((" *+-/"[l]+"(").join(map(str,range(1,v)))+")"*(v-2)or"0")+(l<2>v))

Try the testcases on Try it online!

-9 bytes thanks to @Mr.Xcoder!

-2 bytes thanks to @Felipe Nardi Batista!

Yytsi

Posted 2017-08-03T07:07:03.657

Reputation: 3 582

Fails for 6!. It should be 720. – Mr. Xcoder – 2017-08-03T08:08:50.347

I updated the Tio test suite. – Mr. Xcoder – 2017-08-03T08:23:34.490

-3 bytes. – Mr. Xcoder – 2017-08-03T08:25:07.027

Oh yeah, sure, didn't spot that – Mr. Xcoder – 2017-08-03T08:26:35.303

121 bytes – Mr. Xcoder – 2017-08-03T08:28:09.810

2Behold ES6 – Erik the Outgolfer – 2017-08-03T09:23:08.413

-2 bytes – Felipe Nardi Batista – 2017-08-07T14:44:40.207

4

R, 113 111 bytes

function(s){z=strtoi((n=strsplit(s,'!')[[1]])[1])
n=length(n)
`if`(z,Reduce(c('*','+','-','/')[n],1:z,,T),n<2)}

Try some test cases!

ungolfed:

function(s){
  n <- strsplit(s,"!")[[1]]          # split on "!"
  z <- strtoi(n[1])                  # turn to integer
  n <- length(n)                     # count number of "!"
  FUN <- c(`*`,`+`,`-`,`/`)[[n]]     # select a function
  right <- TRUE                      # Reduce (fold) from the right
  if( z > 0)                         # if z > 0
    Reduce(FUN, 1:z,,right)          # return the value
  else    
    (n < 2)                          # 1 if n = 1, 0 if n > 1
}

Giuseppe

Posted 2017-08-03T07:07:03.657

Reputation: 21 077

el(strsplit(s,"!")) saves 1 byte – bouncyball – 2017-08-03T16:18:13.483

3

Pyth, 34 30 bytes

+uv++H@"/*+-"/Q\!G_tUK.vQKq"0!

Try it online!

Explanation

+uv++H@"/*+-"/Q\!G_tUK.vQKq"0!"Q    Implicit: append "Q
                                    Implicit: read input to Q
                      .vQ           Evaluate Q as Pyth code. This evaluates the integer,
                                    any !'s are parsed as unary NOT for the next expression
                                    and discarded.
                     K              Save the result to K.
                    U               Get a list [0, 1, ..., K-1].
                   t                Drop the first item to get [1, 2, ..., K-1].
                  _                 Reverse to get [K-1, K-2, ..., 1].
 u                       K          Starting from G = K, for H in [K-1, K-2, ..., 1] do:
             /Q\!                     Count the !'s in Q.
      @"/*+-"                         Get the correct operator.
    +H                                Prepend the current H.
   +             G                    Append the previous value G.
  v                                   Evaluate as Python code.
                          q"0!"Q    See if Q == "0!".
+                                   If so, add 1.

PurkkaKoodari

Posted 2017-08-03T07:07:03.657

Reputation: 16 699

Using .U saves a byte. – Erik the Outgolfer – 2017-08-03T10:30:10.933

2

Ruby, 83 80 79 bytes

->s{z=s.count ?!;s<?1?1+1<=>z:eval([*1..w=s.to_i]*(".0"+"_*+-/"[z]+?()+?)*~-w)}

Try it online!

Explanation:

->s{
    # Get number of !
    z=s.count ?!

    # Special case: if the number is 0, then output 0 or 1 depending on z
    s<?1?1+1<=>z:

    # Otherwise build the full expression as a string and then evaluate it
    eval([*1..w=s.to_i]*(".0"+"_*+-/"[z]+?()+?)*~-w)
}

G B

Posted 2017-08-03T07:07:03.657

Reputation: 11 099

2

05AB1E, 27 bytes

þL"/*+-"¹'!¢©è".»"ì.VD_нi®Θ

Try it online!

Erik the Outgolfer

Posted 2017-08-03T07:07:03.657

Reputation: 38 134

DO you know why „.» doesn't work? – Riley – 2017-08-03T13:08:32.007

@Riley » is part of an unfinished compressed string, so it errors out and, as usually in 05AB1E, the error is ignored. – Erik the Outgolfer – 2017-08-03T13:19:45.800

I was trying to do "*+-/"èU then after using L follow up with .»X but it treats X as a string, not a command and .»X.V is even wonkier. – Magic Octopus Urn – 2017-08-03T15:13:42.643

@MagicOctopusUrn X doesn't eval. X.V are two commands. – Erik the Outgolfer – 2017-08-03T15:31:06.263

@EriktheOutgolfer yeah, but I was hoping it'd eval before processing the fold. Hoping, not expecting :(. Could've sworn there was a "use single character String as command in dyadic chain" or something. – Magic Octopus Urn – 2017-08-03T15:32:09.500

@MagicOctopusUrn Umm, what dyadic chain? – Erik the Outgolfer – 2017-08-03T15:38:44.823

Possibly wrong word choice there ._. – Magic Octopus Urn – 2017-08-03T15:41:44.243

2

Haskell, 105 102 98 96 bytes

0!3=0
x!y=foldr([(*),(+),(-),(/)]!!y)([1,0,0,1]!!y)[1..x]
f s|[(n,b)]<-lex s=read n!(length b-1)

Saved 9 bytes thanks to Zgarb and nimi.

Try it online.

Cristian Lupascu

Posted 2017-08-03T07:07:03.657

Reputation: 8 369

@Zgarb You are right. Fixed. – Cristian Lupascu – 2017-08-03T11:30:51.957

I think you can also drop the parens around read n, and f= is unnecessary as per our rules.

– Zgarb – 2017-08-03T11:34:05.640

@Zgarb Right again :) . Thanks! – Cristian Lupascu – 2017-08-03T11:36:36.803

Switching back to a named function and using lex saves two bytes: f s|[(n,b)]<-lex s=read n!(length b-1). – nimi – 2017-08-03T16:06:12.013

@nimi Wow, thanks! I'm so new to Haskell that I didn't even know about lex. That's awesome! :) I don't see how that saves bytes though - I get 99 bytes after this. – Cristian Lupascu – 2017-08-04T06:28:22.617

Your pointfree function is 40 bytes, my version 38 bytes. Compare them.

– nimi – 2017-08-04T15:09:19.230

@nimi Right. I don't know what I was doing wrong earlier. I probably added some whitespace by mistake. – Cristian Lupascu – 2017-08-04T19:23:15.933

2

Java 8, 141 136 134 bytes

s->{float q=s.split("!",-1).length,n=new Float(s.split("!")[0]),i=n,r=n;for(;--i>0;r=q<3?i*r:q<4?i+r:q<5?i-r:i/r);return n<1&q<3?1:r;}

-5 bytes (141 → 136) thanks to @CarlosAlejo's C# answer.

Explanation:

Try it here.

s->{                                // Method with String parameter and float return-type
  float q=s.split("!",-1).length,   //  Amount of exclamation marks + 1
        n=new Float(s.split("!")[0]),
                                    //  The number before the exclamation marks
        i=n,                        //  Index (starting at `n`)
        r=n;                        //  Return sum (starting at `n`)
  for(;--i>0;                       //  Loop from `i-1` down to 1
    r=                              //   Change the result (`r`) to:
      q<3?                          //    If `q` is 2:
       i*r                          //     Multiply
      :q<4?                         //    Else if `q` is 3:
       i+r                          //     Addition
      :q<5?                         //    Else if `q` is 4:
       i-r                          //     Subtraction
      :                             //    Else (if `q` is 5):
       i/r                          //     Division
  );                                //  End of loop
  return n<1&q<3?                   //  Edge case if the input is `0!`:
          1                         //   Then return 1
         :                          //  Else:
          r;                        //   Return the result
}                                   // End of method

Kevin Cruijssen

Posted 2017-08-03T07:07:03.657

Reputation: 67 575

1I have seen a similar answer somewhere else... :-D I keep forgetting that float is shorter than double. – Charlie – 2017-08-03T12:55:34.300

@CarlosAlejo Yeah, I noticed your answer after my initial 141 byte answer. Changing float q=s.length()-(s=s.replace("!","")).length(),n=new Float(s) to the current answer saved me 5 bytes. :) Forgot to add a "bytes saved thanks to" part I noticed now.. Sorry about that. – Kevin Cruijssen – 2017-08-03T13:07:55.177

oh, nevermind that, I'm glad you liked my answer. :-) – Charlie – 2017-08-03T13:24:59.580

2

Jelly,  24 23 26  25 bytes

+ 3  2 bytes patching up to fix after misinterpretation :(

×
+
_
÷
ṣ”!µḢVRṚȯL©Ị$®ŀ@/

A full program (a monadic link with helper links referenced by program location)

Try it online! or see a test suite.

How?

× - Link 1, multiply: number, number

+ - Link 2, add: number, number

_ - Link 1, subtract: number, number

÷ - Link 1, divide: number, number

ṣ”!µḢVRṚȯL©Ị$®ŀ@/ - Main link: list of characters, a
ṣ”!               - split s at '!' characters
   µ              - monadic separation, call that b
    Ḣ             - head - pop and yield the digit list from b, modifying b
     V            - evaluate as Jelly code (get the number, say N)
      R           - range = [1,2,3,...,N]
       Ṛ          - reverse = [N,...,3,2,1]
            $     - last two links as a monad:
         L        -   length of modified b (number of '!' characters)
          ©       -   (copy to register)
           Ị      -   insignificant? (1 when just one '!', 0 when two or more)
        ȯ         - logical or (1 for "0!", 0 for "0!!...", the reversed-range otherwise)
                / - cumulative reduce by:
               @  -  with swapped arguments:
              ŀ   -    dyadic call of link at index:
             ®    -      recall value from register (number of '!' characters)

Jonathan Allan

Posted 2017-08-03T07:07:03.657

Reputation: 67 804

Fails for 0!. – Erik the Outgolfer – 2017-08-03T15:41:23.290

Oh, haha - I had read your comment under the OP wrong - I thought they'd made 0! defined as 0 which would be wrong. – Jonathan Allan – 2017-08-03T15:48:02.077

All fixed up now :) – Jonathan Allan – 2017-08-03T16:08:50.380

Too bad TIO is broken right now so that I can't test if it's still invalid. :( :P Also too bad that you can't use / on an empty list. D: EDIT: Apparently valid for 0!, 0!!, 0!!! and 0!!!!. +1 – Erik the Outgolfer – 2017-08-03T16:51:54.467

2

Self-modifying x86_64 machine code, 123 bytes

0f b6 0f 31 c0 eb 11 0f be c9 8d 04 80 8d 44 41 d0 0f b6 4f 01 48 ff c7 83 f9 21 75 ea b9 21 21 21 a1 33 0f 0f bc c9 81 c1 ff 07 00 00 c1 e9 03 0f b6 c9 89 ca 09 c2 74 35 55 48 89 e5 c7 45 fc 59 58 5c 5e 8a 4c 0d fc 88 0d 15 00 00 00 f3 0f 2a c8 83 f8 02 5d 7c 1f ff c8 0f 57 c0 f3 0f 2a c0 f3 0f 5e c1 83 f8 01 0f 28 c8 7f eb c3 f3 0f 10 05 03 01 00 00 c3 0f 28 c1 c3

Why would interpreted languages be able to dynamically run code with fancy evals, but not plain machine code?

Try it with:

#include <stdio.h>
#include <sys/mman.h>
#include <errno.h>

char ff[] = "\x0f\xb6\x0f\x31\xc0\xeb\x11\x0f\xbe\xc9\x8d\x04\x80\x8d\x44\x41\xd0\x0f\xb6\x4f\x01\x48\xff\xc7\x83\xf9\x21\x75\xea\xb9\x21\x21\x21\xa1\x33\x0f\x0f\xbc\xc9\x81\xc1\xff\x07\x00\x00\xc1\xe9\x03\x0f\xb6\xc9\x89\xca\x09\xc2\x74\x35\x55\x48\x89\xe5\xc7\x45\xfc\x59\x58\x5c\x5e\x8a\x4c\x0d\xfc\x88\x0d\x15\x00\x00\x00\xf3\x0f\x2a\xc8\x83\xf8\x02\x5d\x7c\x1f\xff\xc8\x0f\x57\xc0\xf3\x0f\x2a\xc0\xf3\x0f\x5e\xc1\x83\xf8\x01\x0f\x28\xc8\x7f\xeb\xc3\xf3\x0f\x10\x05\x03\x01\x00\x00\xc3\x0f\x28\xc1\xc3";
int main()
{
    char* page = (char*)((unsigned long)((char*)ff) & (~0xfffLL));
    if (mprotect(page, 0x1000, PROT_READ | PROT_WRITE | PROT_EXEC) < 0) {
        perror("mprotect");
        return -1;
    }
    float (*f)(char*) = (float (*)(char*))ff;
    char* testcases[] = { "0!","1!","2!","3!","4!","5!","6!","7!","8!","9!","10!",
                          "0!!","1!!","2!!","3!!","4!!","5!!","6!!","7!!","8!!","9!!","10!!",
                          "0!!!","1!!!","2!!!","3!!!","4!!!","5!!!","6!!!","7!!!","8!!!","9!!!","10!!!",
                          "0!!!!","1!!!!","2!!!!","3!!!!","4!!!!","5!!!!","6!!!!","7!!!!","8!!!!","9!!!!","10!!!!",
                        };
    for (int i = 0; i < 44; i++) {
        printf("%s -> %f\n", testcases[i], f(testcases[i]));
    }
}

Assembly:

_f:
100000d4f:  0f b6 0f    movzx   ecx, byte ptr [rdi]
100000d52:  31 c0   xor eax, eax
100000d54:  eb 11   jmp 17 <_f+18>
100000d56:  0f be c9    movsx   ecx, cl
100000d59:  8d 04 80    lea eax, [rax + 4*rax]
100000d5c:  8d 44 41 d0     lea eax, [rcx + 2*rax - 48]
100000d60:  0f b6 4f 01     movzx   ecx, byte ptr [rdi + 1]
100000d64:  48 ff c7    inc rdi
100000d67:  83 f9 21    cmp ecx, 33
100000d6a:  75 ea   jne -22 <_f+7>
100000d6c:  b9 21 21 21 a1  mov ecx, 2703302945
100000d71:  33 0f   xor ecx, dword ptr [rdi]
100000d73:  0f bc c9    bsf ecx, ecx
100000d76:  81 c1 ff 07 00 00   add ecx, 2047
100000d7c:  c1 e9 03    shr ecx, 3
100000d7f:  0f b6 c9    movzx   ecx, cl
100000d82:  89 ca   mov edx, ecx
100000d84:  09 c2   or  edx, eax
100000d86:  74 35   je  53 <_f+6E>
100000d88:  55  push    rbp
100000d89:  48 89 e5    mov rbp, rsp
100000d8c:  c7 45 fc 59 58 5c 5e    mov dword ptr [rbp - 4], 1583110233
100000d93:  8a 4c 0d fc     mov cl, byte ptr [rbp + rcx - 4]
100000d97:  88 0d 15 00 00 00   mov byte ptr [rip + 21], cl
100000d9d:  f3 0f 2a c8     cvtsi2ss    xmm1, eax
100000da1:  83 f8 02    cmp eax, 2
100000da4:  5d  pop rbp
100000da5:  7c 1f   jl  31 <_f+77>
100000da7:  ff c8   dec eax
100000da9:  0f 57 c0    xorps   xmm0, xmm0
100000dac:  f3 0f 2a c0     cvtsi2ss    xmm0, eax
100000db0:  f3 0f 5e c1     divss   xmm0, xmm1
100000db4:  83 f8 01    cmp eax, 1
100000db7:  0f 28 c8    movaps  xmm1, xmm0
100000dba:  7f eb   jg  -21 <_f+58>
100000dbc:  c3  ret
100000dbd:  f3 0f 10 05 03 01 00 00     movss   xmm0, dword ptr [rip + 259]
100000dc5:  c3  ret
100000dc6:  0f 28 c1    movaps  xmm0, xmm1
100000dc9:  c3  ret

Explanations will be added later. The basic idea is to modify the divss xmm0, xmm1 instruction at 0x100000db0 and replace it with a mulss, addss, subss or divss according to supplied operand. A small trick is also used to parse the input string.

Assembly generated with:

float f (char* s)
{
    int x;
    for (x=0; *s != '!'; s++) {
        x=10*x + (*s-'0');
    }
    unsigned char op = (__builtin_ctz(*(unsigned int *)s ^ 0xa1212121)-1) >> 3;
    if (x == 0 && op == 0) {
        return 1;
    }
    unsigned int lookup = 0x5e5c5859;
    unsigned char new_code = ((unsigned char*)&lookup)[op];
    asm("movb %0, 0x15(%%rip)" : : "r" (new_code));
    float sum;
    for (sum = x--; x>0; x--) {
        sum = x / sum;
    }
    return sum;
}

yoann

Posted 2017-08-03T07:07:03.657

Reputation: 640

1

Jelly, 28 bytes

×
+
_
÷
³ċ”!
ḟ”!VRṚ¢ŀ@/¢Ị¤¹?

Try it online!

Got the idea of separating the links into lines from Jonathan Allan's answer for -2 bytes.

Erik the Outgolfer

Posted 2017-08-03T07:07:03.657

Reputation: 38 134

1

Gaia, 26 25 bytes

ẋ)@d┅v;l“×+⁻÷”=“ₔ⊢”+e¤ḥ!∨

Try it online!

Explanation

ẋ                          Split the input into runs of the same character.
 )                         Get the last one (the !'s).
  @                        Push an input (since there's none left, use the last one).
   d                       Parse as number (ignores the !'s).
    ┅v                     Get the reverse range: [n .. 1]
      ;                    Copy the ! string
       l“×+⁻÷”=            Get its length and index into this string of operators.
               “ₔ⊢”+       Append 'ₔ⊢' to the operator.
                    e      Eval the resulting string, which is "reduce by <operator> with
                            swapped arguments." Reducing an empty list gives 0.
                     ¤     Bring the !'s back to the top.
                      ḥ!   Remove the first character and check if it's empty.
                        ∨  Logical OR; turns 0 from 0! to 1, doesn't change anything else.

Business Cat

Posted 2017-08-03T07:07:03.657

Reputation: 8 927

1

APL (Dyalog), 30 bytes

Inspired by lstefano's solution.

{0::0⋄(⍎'×+-⌹'⊃⍨≢⍵~⎕D)/⍳⍎⍵∩⎕D}

Try it online!

{} anonymous function where the argument is represented by :

0:: if any error happens:

  0 return zero

 now try:

  ⍵∩⎕D the intersection of the argument and the set of Digits (removes exclamation points)

   execute that (turns it into a number)

  ɩndices of that

  ()/ insert (APL is right associative, as needed) the following function between terms:

   ⍵~⎕D argument without Digits (leaves exclamation points)

   tally that (i.e. how many exclamation points)

  '×+-⌹'⊃⍨ use that to pick from the list of symbols*

   execute (turns the symbol into a function)


(matrix division) is used instead of ÷ (normal division) to cause an error on an empty list

Adám

Posted 2017-08-03T07:07:03.657

Reputation: 37 779

What does :: do in a dfn? – Zacharý – 2017-08-04T22:18:16.050

It is an error guard. If at any point after the error guard is set up, an error with any of the numbers (0=1…999, 1000=1001…) to the left of the :: happens, then the value to the right of the :: is immediately returned.

– Adám – 2017-08-05T22:00:36.567

Well, I never knew about that, thanks! – Zacharý – 2017-08-05T22:20:11.007

0

Perl 5, 96 bytes

s/(\d+)//;@a=1..$1;$"=qw|* + -( /(|[$l=-1+length];$_=$1?"@a".($l>1?')'x($1-1):''):$l?0:1;$_=eval

Try it online!

Xcali

Posted 2017-08-03T07:07:03.657

Reputation: 7 671

0

Dyalog APL, at least 29 chars

{(⍎i⊃'×+-÷')/⍳⍎⍵↓⍨-i←+/'!'=⍵}

The expression is ALMOST correct. It passes all the test cases EXCEPT 0!!!! for which it gives 1 instead of the required 0 and that's because in APL the reduction of an empty vector is supposed to return the neutral element for the function used to reduce. For the quotient that's 1. At the moment I don't have time to try and fix it but I'll leave it here for a rainy day.

lstefano

Posted 2017-08-03T07:07:03.657

Reputation: 850

It is raining: {0::0⋄(⍎'×+-⌹'⊃⍨≢⍵~⎕D)/⍳⍎⍵∩⎕D} Try it online!

– Adám – 2017-08-03T17:56:05.107

Very cool! I don't mind at all if you claim it as your solution, given that the differences are more than the similarities. – lstefano – 2017-08-04T07:53:20.227

Done. – Adám – 2017-08-04T08:05:28.993

0

05AB1E, 25 24 bytes

þDLðýs¹'!¢<"*+-/"ès<×J.V

Try it online!

Magic Octopus Urn

Posted 2017-08-03T07:07:03.657

Reputation: 19 422

0

Mathematica, 152 bytes

(T=ToExpression;If[#=="0!!!!",0,s=T@StringCount[#,"!"];t=T@StringDrop[#,-s];{#!,i~Sum~{i,#},Sum[-i(-1)^i,{i,#}],N@Product[1/i^(-1)^i,{i,#}]}[[s]]&[t]])&

J42161217

Posted 2017-08-03T07:07:03.657

Reputation: 15 931

0

Javascript, 111 163 bytes

s=>([a,b]=s.split(/\b/),c=b.length,a==0&c==1||eval((p=[...Array(+a+1).keys()].slice(1).join(c-1?c-2?c-3?'/(':'-(':'+':'*'))+')'.repeat((p.match(/\(/g)||[]).length)))

Readable Version

s=>([a,b]=s.split(/\b/),c=b.length,a==0&c==1||eval((p=
[...Array(+a+1).keys()].slice(1).join(c-1?c-2?c-3?'/(':'-
(':'+':'*'))+')'.repeat((p.match(/\(/g)||[]).length)))

SuperStormer

Posted 2017-08-03T07:07:03.657

Reputation: 927