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\$
    – xnor
    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\$
    – Gymhgy
    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\$
    – Beefster
    Mar 2, 2019 at 19:32
  • \$\begingroup\$ @KevinCruijssen I don't see why that would matter. 3.7 is between pi and 2pi. \$\endgroup\$
    – Beefster
    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\$
    – MickyT
    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\$ Mar 4, 2019 at 18:27
  • \$\begingroup\$ 56 bytes following xnor's comment about the half-angle formula. \$\endgroup\$
    – Giuseppe
    Mar 6, 2019 at 18:43
  • 1
    \$\begingroup\$ 53 bytes \$\endgroup\$ 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\$
    – xnor
    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\$
    – xnor
    Mar 2, 2019 at 17:41
  • \$\begingroup\$ @xnor Good point. I knew I was using that wrong \$\endgroup\$
    – senox13
    Mar 2, 2019 at 17:43
  • 1
    \$\begingroup\$ You can drop the p= since anonymous functions are ok \$\endgroup\$
    – Quintec
    Mar 2, 2019 at 19:35
  • 1
    \$\begingroup\$ Forgot to update bytecount :) \$\endgroup\$
    – Quintec
    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\$
    – senox13
    Mar 2, 2019 at 21:56
  • \$\begingroup\$ @senox13 Except maybe Stax \$\endgroup\$
    – Gymhgy
    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\$

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

Your Answer

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

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