11
\$\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\$
4
  • 10
    \$\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\$ Commented Mar 2, 2019 at 17:47
  • \$\begingroup\$ Can I take in a dictionary with doubles as its keys? The doubles will be whole numbers, of course. \$\endgroup\$ Commented Mar 2, 2019 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\$ Commented Mar 2, 2019 at 19:32
  • \$\begingroup\$ @KevinCruijssen I don't see why that would matter. 3.7 is between pi and 2pi. \$\endgroup\$ Commented Mar 4, 2019 at 16:29

14 Answers 14

5
\$\begingroup\$

R, 59 53 bytes

function(x,i)x[0:1+i%/%pi]%*%c(a<-cos(i%%pi/2)^2,1-a)

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, and thanks to @RobinRyder for saving a further 3.

\$\endgroup\$
4
  • \$\begingroup\$ I think you can drop a byte with ...*(cos(i%%pi)+1)/2 \$\endgroup\$ Commented Mar 4, 2019 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\$ Commented Mar 4, 2019 at 18:27
  • \$\begingroup\$ 56 bytes following xnor's comment about the half-angle formula. \$\endgroup\$ Commented Mar 6, 2019 at 18:43
  • 1
    \$\begingroup\$ 53 bytes \$\endgroup\$ Commented Jan 10, 2020 at 13:24
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\$
9
  • 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\$ Commented Mar 2, 2019 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\$ Commented Mar 2, 2019 at 17:41
  • \$\begingroup\$ @xnor Good point. I knew I was using that wrong \$\endgroup\$ Commented Mar 2, 2019 at 17:43
  • 1
    \$\begingroup\$ You can drop the p= since anonymous functions are ok \$\endgroup\$ Commented Mar 2, 2019 at 19:35
  • 1
    \$\begingroup\$ Forgot to update bytecount :) \$\endgroup\$ Commented Mar 2, 2019 at 20:42
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\$
3
\$\begingroup\$

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

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

I beat Python! Darn it, Python beat me. I beat Python again!

Try it online!

\$\endgroup\$
2
  • 1
    \$\begingroup\$ Look on the bright side. Neither of us stood a chance against Jelly \$\endgroup\$ Commented Mar 2, 2019 at 21:56
  • \$\begingroup\$ @senox13 Except maybe Stax \$\endgroup\$ Commented Mar 2, 2019 at 22:07
2
\$\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\$

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
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\$
1
\$\begingroup\$

05AB1E, 22 21 20 19 bytes

žq‰`ž>;UÝèÐÁ-θX*-θ

Try it online or verify some more test cases.

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
    ž     # Take the cosine of the remainder
           #  i.e. 2.158... → -0.554...
      >    # Increase it by 1
           #  i.e. -0.554... → 0.554...
       ;   # Halve it
           #  i.e. 0.554... → 0.222...
        U  # Pop and store it in variable `X`
    Ý      # Pop the part, and push a list in the range [0, part]
           #  i.e. 1 → [0, 1]
     è     # (0-based) index all of them into the (implicit) input-list
           #   i.e. [1.3, 3.7, 6.9] and [0, 1] → [1.3, 3.7]
Ð          # Triplicate this list
 Á         # Rotate the last copy once towards the right
           #  i.e. [1.3, 3.7] → [3.7, 1.3]
  -        # Subtract the values in the top two lists from one another
           #  i.e. [1.3, 3.7] and [3.7, 1.3] → [-2.4, 2.4]
   θ       # Pop and only leave the last value of this list
           #  i.e. [-2.4, 2.4] → 2.4
    X*     # Multiply it by `X`
           #  i.e. 2.4 * `X`=0.222... → 0.534...
     -     # Subtract it from each of the values in the list we triplicated
           #  i.e. [1.3, 3.7] - 0.534... → [0.765..., 3.165...]
      θ    # And only leave the last value of this list
           #  i.e. [0.765..., 3.165...] → 3.165...
           # (which is output implicitly as result)
\$\endgroup\$
1
\$\begingroup\$

Ruby, 67 bytes

->a,i{z=Math::PI;Math.cos(i%z/2)**2*(a[-1+j=(i/z).to_i]-a[j])+a[j]}

Try it online!

\$\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\$

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\$
0
\$\begingroup\$

C (GCC) 99 79 bytes

-20 bytes ceilingcat

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

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

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.