| Bytes | Lang | Time | Link |
|---|---|---|---|
| 048 | APLNARS | 250403T061928Z | Rosario |
| 114 | C gcc lm m32 | 200514T000727Z | Mitchell |
| 070 | SageMath | 200514T121755Z | Noodle9 |
| 023 | 05AB1E | 200514T090144Z | Kevin Cr |
| 060 | Python 3 | 200514T114437Z | xnor |
| 071 | Python 3 | 200514T003718Z | svavil |
| 066 | J | 200513T214336Z | Jonah |
| 083 | Python 3 | 200513T230023Z | Surculos |
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 2π, 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)
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)))
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)
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
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.@#@[)]
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.
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
The same solution as below, but uses several approximations:
- \$2\pi \approx 6.2832\$
- \$ \theta\sqrt{1+\theta^2}+\sinh^{-1}\theta + C \$
\$ \approx \theta^2 + \ln(2\theta+0.5) +C \$
\$ \approx \theta^2 + 99(2\theta+0.5)^{0.01} + C\$
"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)
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) $$
