9
\$\begingroup\$

Your task is to take an array of numbers and a real number and return the value at that point in the array. Arrays start at \$\pi\$ and are counted in \$\pi\$ intervals. Thing is, we're actually going to interpolate between elements given the "index". As an example:

Index:    1π   2π   3π   4π   5π   6π
Array: [ 1.1, 1.3, 6.9, 4.2, 1.3, 3.7 ]

Because it's \$\pi\$, we have to do the obligatory trigonometry, so we'll be using cosine interpolation using the following formula:

\${\cos(i \mod \pi) + 1 \over 2} * (\alpha - \beta) + \beta\$

where:

  • \$i\$ is the input "index"
  • \$\alpha\$ is the value of the element immediately before the "index"
  • \$\beta\$ is the value of the element immediately after the "index"
  • \$\cos\$ takes its angle in radians

Example

Given [1.3, 3.7, 6.9], 5.3:

Index 5.3 is between \$1\pi\$ and \$2\pi\$, so 1.3 will be used for before and 3.7 will be used for after. Putting it into the formula, we get:

\${\cos(5.3 \mod \pi) + 1 \over 2} * (1.3 - 3.7) + 3.7\$

Which comes out to 3.165

Notes

  • Input and output may be in any convenient format
  • You may assume the input number is greater than \$\pi\$ and less than array length * \$\pi\$
  • You may assume the input array will be at least 2 elements long.
  • Your result must have at least two decimal points of precision, be accurate to within 0.05, and support numbers up to 100 for this precision/accuracy. (single-precision floats are more than sufficient to meet this requirement)

Happy Golfing!

\$\endgroup\$
  • 8
    \$\begingroup\$ FYI golfers, it might be shorter to write rewrite \$(\cos(x)+1)/2\$ as \$\cos(x/2)^2\$ using the half-angle formula for \$\cos\$. \$\endgroup\$ – xnor Mar 2 at 17:47
  • \$\begingroup\$ Can I take in a dictionary with doubles as its keys? The doubles will be whole numbers, of course. \$\endgroup\$ – Embodiment of Ignorance Mar 2 at 18:55
  • \$\begingroup\$ @EmbodimentofIgnorance, sure. I doubt that's going to help you, but that's a perfectly reasonable representation of arrays since that's how Lua does it. \$\endgroup\$ – Beefster Mar 2 at 19:32
  • \$\begingroup\$ @KevinCruijssen I don't see why that would matter. 3.7 is between pi and 2pi. \$\endgroup\$ – Beefster Mar 4 at 16:29

13 Answers 13

4
\$\begingroup\$

Python 3.8 (pre-release), 85 74 bytes

-8 bytes thanks to @xnor
-2 bytes thanks to @Quintec

This takes advantage of the Python 3.8 pre-release's new := assignment operator. Other than that, this is really just the equation written out in Python.

import math
lambda l,i:cos(i%math.pi/2)**2*(l[(j:=int(i/pi))-1]-l[j])+l[j]

Usage:

>>> p=lambda l,i:cos(i%math.pi/2)**2*(l[(j:=int(i/pi))-1]-l[j])+l[j]
>>> print(p([1.3, 3.7, 6.9],5.3))
3.165249203414993

Try it online!

\$\endgroup\$
  • 1
    \$\begingroup\$ You can just assign j the first place it's mentioned -- part of the power of assignment expressions is that they evaluate to the value as well as assigning it. \$\endgroup\$ – xnor Mar 2 at 17:10
  • 1
    \$\begingroup\$ Another byte save: Use trig identities to convert (cos(i%pi)+1)/2 to cos(i%pi/2)**2 \$\endgroup\$ – xnor Mar 2 at 17:41
  • \$\begingroup\$ @xnor Good point. I knew I was using that wrong \$\endgroup\$ – senox13 Mar 2 at 17:43
  • 1
    \$\begingroup\$ You can drop the p= since anonymous functions are ok \$\endgroup\$ – Quintec Mar 2 at 19:35
  • 1
    \$\begingroup\$ Forgot to update bytecount :) \$\endgroup\$ – Quintec Mar 2 at 20:42
4
\$\begingroup\$

R, 59 56 bytes

function(x,i)(y=x[0:1+i%/%pi])[2]-diff(y)*cos(i%%pi/2)^2

Try it online!

Nothing too clever here - just an R version of the formula in the question. Thanks @MickyT for saving a byte, and to @Giueseppe and indirectly @xnor for another two.

\$\endgroup\$
  • \$\begingroup\$ I think you can drop a byte with ...*(cos(i%%pi)+1)/2 \$\endgroup\$ – MickyT Mar 4 at 18:24
  • \$\begingroup\$ @MickyT thanks, I had originally put the +1 in the parentheses, but had added a redundant pair of parentheses so ending up with 60 bytes \$\endgroup\$ – Nick Kennedy Mar 4 at 18:27
  • \$\begingroup\$ 56 bytes following xnor's comment about the half-angle formula. \$\endgroup\$ – Giuseppe Mar 6 at 18:43
3
\$\begingroup\$

Jelly, 17 bytes

d©ØPṪÆẠ‘H×I_@Ḋ}®ị

A full program accepting \$i\$ and the array which prints the interpolated value.

Try it online!

How?

Interpolates between all neighbours using \$\frac{\cos(i \mod \pi)+1}2\$ then picks the relevant value.

d©ØPṪÆẠ‘H×I_@Ḋ}®ị - Link: number, i; list of numbers, A
  ØP              - pi (ish) = 3.141592653589793
d                 - divmod = [i//pi, i%pi]
 ©                - (copy to register for later)
    Ṫ             - tail (gets i%pi leaving register copy as [i//pi])  
     ÆẠ           - cosine = cos(i%pi)
       ‘          - increment
        H         - halve
         ×        - multiply by A (vectorises)
          I       - increments -- i.e. (cos(i%pi)+1)(r-l)/2 for neighbours [l,r]
             Ḋ}   - dequeue A
           _@     - swapped arg subtract (vectorises) -- i.e. r-(cos(i%pi)+1)(r-l)/2
                  -                                         = r+(cos(i%pi)+1)(l-r)/2
               ®  - recall value from the register
                ị - index into (vectorises) -- i.e. [β+(cos(i%pi)+1)(α-β)/2]
                  - implicit print of Jelly representation (only 1 entry so [] wont appear)
\$\endgroup\$
1
\$\begingroup\$

Röda, 51 bytes

f a,i{j=i//PI;[(cos(i%PI)+1)/2*(a[j-1]-a[j])+a[j]]}

Try it online!

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

Stax, 17 bytes

≈ëBü☺ÆssÅ¢â)KjjïΔ

Run and debug it

Unpacked, ungolfed, and commented it looks like this.

VP|%    divmod with pi;  push div and mod results separately
|7^h    do (cos(modpart) + 1) / 2
sX      swap the original div result to top of stack, store it in the x register
v       decrement
;:-     pairwise differences of array
@       get element at index
N*      negate and multiply
;x@     get element from the original array at the x index, where x is the register
+       add

Run this one

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

Japt, 47 46 38 bytes

u0;J=V/MP[A=UgJc) nUgJf))½McVuMP)Ä]×+A

To be continued... (golfing)

Try it online!

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

C# (Visual C# Interactive Compiler), 76 bytes

n=>m=>(Math.Cos(m%Math.PI)+1)/2*(n[t=(int)(m/Math.PI)-1]-n[++t])+n[t];int t;

I beat Python! Darn it, Python beat me.

Try it online!

\$\endgroup\$
  • 1
    \$\begingroup\$ Look on the bright side. Neither of us stood a chance against Jelly \$\endgroup\$ – senox13 Mar 2 at 21:56
  • \$\begingroup\$ @senox13 Except maybe Stax \$\endgroup\$ – Embodiment of Ignorance Mar 2 at 22:07
1
\$\begingroup\$

APL+WIN, 39 37 bytes

2 bytes saved thanks to Adám

2⊃m+(-/m←⎕[0 1+⌊n÷○1])÷2÷1+2○(○1)|n←⎕

Try it online!Dyalog Classic

Explanation:

n←⎕ prompt for input of integer

2÷1+2○(○1)|n evaluate first term of formula

[0 1+⌊n÷○1] identify indices of alpha and beta

m←⎕[...] prompt for input of vector and select alpha and beta

-/m alpha-beta

2⊃m+ take result of adding beta to complete the equation 
\$\endgroup\$
1
\$\begingroup\$

Haskell, 65 bytes

v!i|(c,r)<-properFraction$i/pi=cos(r*pi/2)^2*(v!!(c-1)-v!!c)+v!!c

Try it online!

Note: the array is represented as a list.

Thanks to @xnor for the half-angle tip.

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

Jelly, 23 20 18 bytes

³%ØPÆẠ×_++H
÷ØPịÇ/

Try it online!

÷ØPịṁؽµ³%ØPÆẠ×I_@SH    Dyadic link, arguments x (index) and Z (array):
֯P                     x/pi
   ị                    Index (into Z).
                        When x/pi is an integer, returns that elt of Z.
                        Otherwise returns 2 elements at floor and ceiling.
     ؽ                   [1,2] (generic 2 element array)
    ṁؽ                 Mold; shape like [1,2] to ensure we have 2 elements.
       µ                Start a new, monadic chain with the result [a,b]
        ³%ØPÆẠ×I_@SH    Monadic chain
        ³               x
         %ØP            x mod pi
            ÆẠ          Unarccosine; cos(x mod pi).
               I          Increment; b-a.
              ×I        (b-a) cos(x mod pi)
                  S       a+b
                _@S     a + b - (b-a) cos(x mod pi)
                   H    Halve; this is equivalent to our desired result.
\$\endgroup\$
0
\$\begingroup\$

05AB1E, 22 21 bytes

žq‰`;žnU©èV®<èY-X*Y+

Try it online.

21-bytes alternative:

žq‰`ž>;sUI¥X<è(*IXè+

Try it online.

Explanation:

žq‰         # Take the divmod PI of the (implicit) input-decimal
            # (part = input integer-divided by PI, remainder = input modulo-PI)
            #  i.e. 5.3 → [1,2.158...]
   `        # Push both values separately to the stack
    ;       # Halve the remainder
            #  i.e. 2.158... → 1.079...
     ž     # Take the cosine of that
            #  i.e. 1.079... → 0.472...
       n    # Then the square of that
            #  i.e. 0.472... → 0.222...
        U   # Pop and store it in variable `X`
    ©       # Store the part in variable `r` (without popping)
     è      # Index it into the (implicit) input-list
            #  i.e. [1.3,3.7,6.9] and 1 → 3.7
      V     # Pop and store it in variable `Y`
    ®<è     # Index `r`-1 also into the (implicit) input-list
            #  i.e. [1.3,3.7,6.9] and 0 (1-1) → 1.3
    Y-      # Subtract variable `Y` from this
            #  i.e. 1.3 - `Y`=3.7 → -2.4
    X*      # Then multiply it by variable `X`
            #  i.e. `X`=0.222... * -2.4 → -0.534...
    Y+      # And add variable `Y` again
            #  i.e. -0.534... + `Y`=3.7 → 3.165...
            # (then output implicitly as result)
\$\endgroup\$
0
\$\begingroup\$

C (GCC) 99 bytes

float P=2*acos(0);
#define f(i,a)(cos(fmod(i,P))+1)/2*(a[(int)(i/P)-1]-a[(int)(i/P)])+a[(int)(i/P)]

Try it online

Calling code

int main() {
  float a[3] = {1.3,3.7,6.9};
  printf("%f\n", f(5.3,a));
}

note that it needed the compiler flag -lm to link with math libraries, so +3 bytes if you count that.

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

Attache, 54 bytes

${Cos[y%PI/2]^2*&`-@(j:=x[1'-1*Floor[y'-y/PI]-1])+j@1}

Try it online!

Explanation

${Cos[y%PI/2]^2*&`-@(j:=x[1'-1*Floor[y'-y/PI]-1])+j@1}
${                                                   }  parameters: x, y
  Cos[y%PI/2]^2                                         the scaling function factor
               *                                        times
                     j:=                                set j to
                        x[                     ]        the element in x at
                          1'-1*Floor[y'-y/PI]-1         the closest indices scaled by PI
                &`-@(                           )       spread subtraction over bounds
                                                 +j@1   add the upper bound
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.