g | x | w | all
Bytes Lang Time Link
048APLNARS250403T061928ZRosario
114C gcc lm m32200514T000727ZMitchell
070SageMath200514T121755ZNoodle9
02305AB1E200514T090144ZKevin Cr
060Python 3200514T114437Zxnor
071Python 3200514T003718Zsvavil
066J200513T214336ZJonah
083Python 3200513T230023ZSurculos

APL(NARS), 48 chars

{(i r g)←⍵⋄(a b)←(○2)×r,i÷g⋄1⍕(g÷○2)×b{4○⍵}∫a+b}

It calculate the integral (g÷○2)×b{4○⍵}∫a+b, where ○2 is , a is 2πr, b is 2πi÷g, and {4○⍵} is the function {√1+⍵*2}. Test:

  f←{(i r g)←⍵⋄(a b)←(○2)×r,i÷g⋄1⍕(g÷○2)×b{4○⍵}∫a+b}
  f 5 3 4
207.7
  f 0 1 1
3.4
  f 12 9 2
1187.7

C (gcc) -lm -m32, 129 120 117 114 bytes

#define F float
F i(F u,F g){F s=hypot(u,g/=6.2832);return(u*s/g+g*log(s+u))/2;}
#define f(I,R,G)i(I+G*R,G)-i(I,G)

Try it online!

5 bytes off thanks to ceilingcat (by using the hypot library function).

4 bytes off thanks to dingledooper (who suggested using a typedef to shorten the float declarations -- I ended up using a macro instead to implement the same idea).

3 bytes off by using an approximation to \$2\pi\$ that's sufficient for the accuracy required by the challenge.

3 more bytes thanks to ceilingcat (turning f from a function into a macro).

The auxiliary function i computes the appropriate indefinite integral, and then f computes the desired definite integral by evaluating the indefinite integral at the two endpoints and subtracting.

SageMath, 70 bytes

lambda I,R,G:N(G/2/pi*(sqrt(1+x^2)).integral(x,2*pi*I/G,2*pi*(I/G+R)))

Try it online!

How

Uses the formula for the length of the spiral: $$ L=\frac{G}{2\pi} \int_{\frac{2\pi I}{G}}^{\frac{2\pi(I+GR)}{G}}\sqrt{1+\theta^2}d\theta $$

from Surculose Sputum's Python answer.

05AB1E, 23 bytes

4°©*Ý*®/+nŽ›Ñ₄/*²n+tO®/

Port of @svavil's Python answer (their revision without complex number), so make sure to upvote them!

Input-order as r,g,i.

Try it online or verify all test cases.

Explanation:

4°                      # Push 10**4: 10000
  ©                     # Store it in variable `®` (without popping)
   *                    # Multiply it by the first (implicit) input `r`
    Ý                   # Push a list in the range [0, 10000r]
     *                  # Multiply each value by the second (implicit) input `g`
      ®/                # Divide each by `®`
        +               # Add the third (implicit) input `i` to each value
         n              # Take the square of that
          Ž›Ñ           # Push compressed integer 39478
             ₄/         # Divide it by 1000: 39.478
               *        # Multiply it by each value
                ²       # Push the second input `g` again
                 n      # Square it
                  +     # And add it to each value as well
                   t    # Take the square-root of each value
                    O   # Sum everything together
                     ®/ # And divide it by `®`
                        # (after which the result is output implicitly)

See this 05AB1E tip of mine (section How to compress large integers?) to understand why Ž›Ñ is 39478.

Python 3, 60 bytes

lambda I,R,G:6.2831*R*(I+R*G/2)+G*8*((1+R/(I/G+.05))**.01-1)

Try it online!

An approximate method. Approximates log without an import using Surculose Sputum's nifty approximation

This approximation is quite accurate, achieving within 0.02 on all the test cases and within 0.1 on all single-digit inputs. It's possible to use looser approximations that work for all the test cases, but I'm not sure at what point this is overfitting. In the extreme, hardcoding the outputs would be very short. So, I'd like to exclude this answer from my bounty on outgolfing me since I'm not clear what golfs what be valid.

The first summand \$2\pi(I+RG/2)R\$ is what we get if we approximate the toilet paper spiral as instead being concentric circles with the same inner radius, thickness, and number of turns. The average of the circumferences of these \$R\$ circles is \$2\pi(I+RG/2)\$. This is \$2\pi\$ times the average of their radii of \$I+RG/2\$, or equivalently the average of the inner and outer radius.

The above approximation is already pretty good for the test cases, with error within 0.4. The second term approximates the additional circumference due to the spiral moving radially, rather than just tangentially as circles do. I got this from looking at the integral for arc length suggested by svavil. We then get rid of approximate log without an import using Surculose Sputum's approximation The constant of 8 is an approximation for \$100/(4\pi)\$, with 100 being inverse of the exponent 0.01 chosen for the log approximation. The +0.05 fixes an approximation failing near \$I/G=0\$, which would otherwise cause a divide-by-zero. I originally calculated the desired values as \$1/(4\pi)=0.08\$, but heuristically 0.05 does better.

Python 3, 93 83 76 71 bytes

-9 bytes if we don't explicitly round the results
-1 byte after changing n to 9999
-7 bytes thanks to dingledooper who rearranged the operations
-5 bytes thanks to xnor who changed the square root calculations to taking an absolute value of a complex number

lambda i,r,g:sum(abs(1j+6.283*(t/n+i/g))for t in range(n*r))/n*g
n=9999

Try it online!

This is a straightforward numerical integration of a spiral length, without using any imports. n is chosen so that the results are sufficiently precise.

The length of a spiral is a sum $$L = \sum_{t=1}^n L_t,$$ where Lt is calculated as a hypothenuse in a roughly right triangle with sides $$\frac{2\pi}{n} r_t = \frac{2\pi}{n}\left(i+\frac{gt}{n}\right)$$ and $$r_{t+1}-r_t = \frac{g}{n}$$.

J, 66 bytes

1#.2|@-/\1e3&((-:@[%:_1:)^[:i.1+[*0{])((*{:)+[*(1{])*1e3%~i.@#@[)]

Try it online!

This could be golfed more, but I'm putting it away for now.

Instead of taking an analytic approach I am using complex number arithmetic to break the spiral down into 1000 straight line segments per rotation, and then summing those segments.

I find the 500th root of -1, and keep multiplying it by itself to rotate it and get an approximation to the next spiral point.

Because the spiral also moves outward, we need to take the new vector, normalize it, multiply the normal vector by 1/1000 of the thickness, and then add that little correction to the new vector.

Conceptually, we're doing something similar to approximating a circle's circumference with the short sides of many triangles.

enter image description here

The idea is simple, but the golf part of it boils down to boring bookkeeping and argument parsing which isn't worth going into. In theory the realization of this method could be a lot shorter.

Python 3, 83 bytes

Thanks @xnor for finding some important approximation, notably h(t)=t*t+log(2*t+.5)

lambda i,r,g:g/2/T*(h(T*(i/g+r))-h(T*i/g))
h=lambda t:t*t+99*(2*t+.5)**.01
T=6.2832

Try it online!

The same solution as below, but uses several approximations:


"Exact" solution

Python 3, 104 100 bytes

-3 bytes thanks to @mathjunkie!
-1 byte thanks to @xnor!

lambda i,r,g:g/4/pi*(h(2*pi*(i/g+r))-h(2*pi*i/g))
from math import*
h=lambda t:t*hypot(t,1)+asinh(t)

Try it online!

This uses the exact formula. Maybe a good Taylor series approximation can be shorter.

The formula for the length of the spiral is: $$ L=\frac{G}{2\pi} \int_{\frac{2\pi I}{G}}^{\frac{2\pi(I+GR)}{G}}\sqrt{1+\theta^2}d\theta $$ and the formula for the integral is: $$ \int \sqrt{1+\theta^2}d\theta=\frac{1}{2}\left(\theta\sqrt{1+\theta^2}+\sinh^{-1}\theta \right) $$