pensar más allá

16

Está tratando de encajar una esfera en una caja de 5 lados, pero a veces no cabe completamente. Escribe una función para calcular la cantidad de la esfera que está fuera (por encima del borde) del cuadro.

Hay 3 situaciones posibles:

  • La esfera cabe completamente en la caja. La respuesta será 0.
  • La esfera se encuentra en el borde de la caja. La respuesta será más de la mitad del volumen total.
  • La esfera se encuentra en el fondo de la caja.

Puedes ver cada situación aquí:

Imagen

Debe escribir un programa o función para calcular este valor en al menos 4 dígitos significativos.

Entrada: 4 números reales no negativos en cualquier formato que sea conveniente *: ancho, largo, profundidad de la caja (medidas interiores) y diámetro de la esfera.

Salida: 1 número real no negativo en un formato utilizable *: el volumen total (no el porcentaje) de la esfera fuera de la caja.

* debe ser convertible a / desde una cadena decimal

Se le recomienda que limite su uso de trigonometría tanto como sea posible.

Este es un concurso de popularidad, ¡así que piense fuera de la caja!

Kendall Frey
fuente
algún caso de ejemplo por favor?
mniip
1
¿Podemos suponer que las paredes de la caja son infinitamente delgadas o que las dimensiones dadas son dimensiones interiores? :)
Darren Stone
¿Cuáles son los valores máximos para las entradas?
Blender
@DarrenStone Creo que el grosor de las paredes no es importante. También podría considerarlo infinito, por lo que la caja sería un agujero rectangular en un bloque infinito. El resultado sería el mismo que cualquier otro valor para el grosor de la pared. Excepto si tiene la intención de doblar / engañar las reglas rompiendo, distorsionando o cortando la caja o la esfera, o haciendo algo realmente extraño.
Victor Stafusa
3
@DarrenStone Las cajas solo tienen grosor para una buena imagen. El problema trata con las dimensiones interiores.
Kendall Frey

Respuestas:

21

Adelante

Encuentra, debajo, una esfera fuera de la caja.

La "esfera" es la función de cálculo de volumen f. Los casos de prueba de referencia componen la "caja".

                     ( x y z d -- v )
                 : f { F: z F: d } d f2/ 
              { F: r } fmin { F: m } m f2/ {
             F: b } d m f<= d z f<= and if 0e
             else r r r f* b b f* f- fsqrt f-
              { F: t } d m f<= t z f> or if d 
               z f- else d t f- then r 3e f* 
                  fover f- pi f* fover f*
                      f* 3e f/ then ;

                     1e                 1e      
                     1e                 1e 
                     f                  f. 
            cr       1e        1e       0e      
            1e       f         f.       cr 
            1e       1e 0.5e 1e f f. cr 1e 
            0.999e 1e          1e     f  
            f.  cr            0.1e 1e   
            1.000e 0.500e f f. cr

Salida:

0. 
0.523598775598299 
0.261799387799149 
0.279345334323962 
0.0654299441440212 
Piedra de Darren
fuente
5

Java - basado en enteros

Este programa no usa pi y no llama a ninguna función externa, ni siquiera sqrt. Sólo utiliza aritmética simple - +, -, *y /. Además, aparte de un paso de escala, funciona exclusivamente con enteros. Básicamente divide la esfera en pequeños cubos y cuenta los que están fuera de la caja.

public class Box {
    private static final int MIN = 10000;
    private static final int MAX = MIN * 2;

    private static final int[] SQ = new int[MAX * MAX + 1];

    static {
        int t = 1;
        for (int i = 1; i <= MAX; ++i) {
            while (t < i * i) SQ[t++] = i - 1;
        }
        SQ[MAX * MAX] = MAX;
    }

    public static long outsideInt(int r, int w, int z) {
        int r2 = r * r;
        int o = z - r + 1;
        if (w < r * 2) {
            int t = 1 - SQ[r2 - w * w / 4];
            if (t < o) o = t;
        }
        long v = 0;
        for (int i = o; i <= r; ++i) {
            int d = r2 - i * i;
            int j0 = SQ[d];
            v += 1 + 3 * j0;
            for (int j = 1; j <= j0; ++j)
                v += 4 * SQ[d - j * j];
        }
        return v;
    }

    public static double outside(double x, double y, double z, double d) {
        double f = 1;
        double w = x < y ? x : y;
        double r = d / 2;
        while (r < MIN) {
            f *= 8;
            r *= 2;
            w *= 2;
            z *= 2;
        }
        while (r > MAX) {
            f /= 8;
            r /= 2;
            w /= 2;
            z /= 2;
        }
        return outsideInt((int) r, (int) w, (int) z) / f;
    }

    public static void main(final String... args) {
        System.out.println(outside(1, 1, 1, 1));
        System.out.println(outside(1, 1, 0, 1));
        System.out.println(outside(1, 1, 0.5, 1));
        System.out.println(outside(1, 0.999, 1, 1));
        System.out.println(outside(0.1, 1, 1, 0.5));
    }
}

Salida:

0.0
0.5235867850933005
0.26178140856157484
0.27938608275528054
0.06542839088004015

De esta forma, el programa requiere más de 2 GB de memoria (funciona -Xmx2300maquí) y es bastante lento. Utiliza la memoria para calcular previamente un montón de raíces cuadradas (aritméticamente); no es realmente necesario, pero sin eso sería MUCHO más lento. Para mejorar las necesidades de memoria y la velocidad, reduzca el valor de la MINconstante (aunque eso disminuirá la precisión).

aditsu
fuente
2

Python 2 (enfoque basado en matriz)

Crea una matriz de matrices con valores de verdad si un cuadrado específico en esa cuadrícula está dentro del círculo o fuera del círculo. Debería ser más preciso cuanto mayor sea el círculo que dibujes. Luego selecciona un área debajo o encima de una fila determinada y cuenta la cantidad de cuadrados que pertenecen al círculo y la divide por la cantidad de cuadrados que están en todo el círculo.

import math as magic
magic.more = magic.pow
magic.less = magic.sqrt

def a( width, length, depth, diameter ):
  precision = 350 #Crank this up to higher values, such as 20000

  circle = []
  for x in xrange(-precision,precision):
    row = []
    for y in xrange(-precision,precision):
      if magic.less(magic.more(x, 2.0)+magic.more(y, 2.0)) <= precision:
        row.append(True)
      else:
        row.append(False)
    circle.append(row)

  if min(width,length,depth) >= diameter:
    return 0
  elif min(width,length) >= diameter:
    row = precision*2-int(precision*2*float(depth)/float(diameter))
    total = len([x for y in circle for x in y if x])
    ammo = len([x for y in circle[:row] for x in y if x])
    return float(ammo)/float(total)
  else:
    #Why try to fit a sphere in a box if you can try to fit a box on a sphere
    maxwidth = int(float(precision*2)*float(min(width,length))/float(diameter))
    for row in xrange(0,precision*2):
      rowwidth = len([x for x in circle[row] if x])
      if rowwidth > maxwidth:
        total = len([x for y in circle for x in y if x])
        ammo = len([x for y in circle[row:] for x in y if x])
        return float(ammo)/float(total)
Sumurai8
fuente
2

Python 2.7, Fórmula de tapa esférica

Esta versión arrojará una advertencia de tiempo de ejecución en algunos casos, pero aún muestra la respuesta correcta.

import numpy as n
x,y,z,d=(float(i) for i in raw_input().split(' '))
r=d/2
V=4*n.pi*r**3/3
a=n.sqrt((d-z)*z)
b=min(x,y)/2
h=r-n.sqrt(r**2-b**2)
c=lambda A,H: (3*A**2+H**2)*n.pi*H/6
print(0 if d<=z and r<=b else c(a,d-z) if r<=b and z>r else V-c(a,z) if r<=b or z<h else V-c(b,h))

Para 11 caracteres más, puedo deshacerme de la advertencia.

import math as m
x,y,z,d=(float(i) for i in raw_input().split(' '))
r=d/2
V=4*m.pi*r**3/3
if d>z:
    a=m.sqrt((d-z)*z)
b=min(x,y)/2
h=r-m.sqrt(r**2-b**2)
c=lambda A,H: (3*A**2+H**2)*m.pi*H/6
print(0 if d<=z and r<=b else c(a,d-z) if r<=b and z>r else V-c(a,z) if r<=b or z<h else V-c(b,h))

Estos son los casos de prueba ejecutados en la versión 1:

$ python spherevolume.py
1 1 1 1
0
$ python spherevolume.py
1 1 0 1
0.523598775598
$ python spherevolume.py
1 1 .5 1
0.261799387799
$ python spherevolume.py
1 .999 1 1        
0.279345334324
$ python spherevolume.py
.1 1 1 0.5
spherevolume.py:65: RuntimeWarning: invalid value encountered in sqrt
  a=n.sqrt((d-z)*z) or b
0.065429944144
usuario2487951
fuente
A pesar de que esto no es un código de golf, se puede acortar import numpy as na from numpy import*y quitar todo el n.en el código.
Timtech
@Timtech Gracias por el aviso y sugerencia.
user2487951
1

Mathematica

Uso de integración numérica con límites adecuados.

f[width_, length_, height_, diam_] := 
 With[{r = diam/2, size = Min[width, length]/2},
  Re@NIntegrate[
    Boole[x^2 + y^2 + z^2 < r^2], {x, -r, r}, {y, -r, r}, 
      {z, -r, Max[-r, If[size >= r, r - height, Sqrt[r^2 - size^2]]]}]
  ]
silbido
fuente
0

Implementación de referencia - C #

using System;

namespace thinkoutsidethebox
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine(OutsideTheBox(1, 1, 1, 1));
            Console.WriteLine(OutsideTheBox(1, 1, 0, 1));
            Console.WriteLine(OutsideTheBox(1, 1, 0.5, 1));
            Console.WriteLine(OutsideTheBox(1, 0.999, 1, 1));
            Console.WriteLine(OutsideTheBox(0.1, 1, 1, 0.5));
        }

        static double OutsideTheBox(double x, double y, double z, double d)
        {
            x = Math.Min(x, y);
            double r = d / 2; // radius
            double xr = x / 2; // box 'radius'
            double inside = 0; // distance the sphere sits inside the box
            if (d <= x && d <= z) // it fits
            {
                return 0;
            }
            else if (d <= x || r - Math.Sqrt(r * r - xr * xr) > z) // it sits on the bottom
            {
                inside = z;
            }
            else // it sits on the rim
            {
                inside = r - Math.Sqrt(r * r - xr * xr);
            }
            // now use the formula from Wikipedia
            double h = d - inside;
            return (Math.PI * h * h / 3) * (3 * r - h);
        }
    }
}

Salida:

0
0.523598775598299
0.261799387799149
0.279345334323962
0.0654299441440212
Kendall Frey
fuente
No entiendo estos resultados. El primero es obviamente 0. El segundo no tiene altura, por lo que uno debe ser 1. El tercero puede albergar la pelota, y exactamente la mitad está por encima (la respuesta debe ser 0.5). La caja en el caso 4 es un poco pequeña, por lo que descansa sobre la caja. La respuesta debería ser un poco más de 0.5. La respuesta para el último debe ser> 0.5, ya que el ancho / largo no es suficiente para encajar la pelota dentro.
Sumurai8
@ Sumurai8 "Salida: el volumen total ( no el porcentaje ) de la esfera fuera de la caja".
Kendall Frey
0

Rubí

Veamos ...
Si la caja está completamente adentro, entonces ancho> diámetro; longitud> diámetro y altura> diámetro.
Esa debería ser la primera verificación que se ejecute.

Si se encuentra en la parte inferior, entonces w> d; l> d y h V=(pi*h^2 /3)*(3r-h)Entonces, en ese caso, solo obtenemos la altura y la pasamos por eso.

Si está atascado, usamos una fórmula similar ( V=(pi*h/6)*(3a^2 + h^2)). De hecho, nuestra fórmula anterior se basa en esta. Esencialmente, usamos eso, y a es simplemente el más pequeño de w y l. (pista, podemos obtener altura haciendo h=r-a)

¡Ahora el código!

def TOTB(wi,le,hi,di)
  if wi>=di and le>=di and hi>=di
    res = 0
  elsif wi>=di and le>=di
    r = di/2
    res = 3*r
    res -= hi
    res *= Math::PI
    res *= hi*hi
    res /= 3
  else
    r = di/2
    if wi>le
      a=le
    else
      a=wi
    end #had issues with the Ternary operator on ruby 2.2dev
    h = r-a
    res = 3*a*a
    res += h*h
    res *= Math::PI
    res *= h
    res /= 6
  end
  res
end

Nota ** No lo probé demasiado, por lo que es posible que se haya introducido un error, si alguien lo nota, ¡dígalo!
Sin embargo, las matemáticas son sólidas.
Versión más corta:

v1 = ->r,h{(3*r -h)*Math::PI*h*h/3}
v2 = ->r,a{h=r-a;((3*a*a)+(h*h))*h*Math::PI/6}
TOTB = ->wi,le,hi,di{(di<wi&&di<le&&di<hi)?0:((di<wi&&di<le)?v1[di/2,hi]:v2[di/2,((wi>le)?le:wi)])}

(Ahora sé con certeza que obtener h para v2 se realiza de manera diferente, pero lo arreglaré más adelante.


fuente
Agradable. Ese código se lee claramente. Pero, ¿estás seguro de la siguiente declaración? "podemos obtener altura haciendo h=r-a" Estaba leyendo las fórmulas esféricas de la tapa , y el diagrama no sugiere una relación tan simple. Le daré otra lectura.
Darren Stone el
@DarrenStone Ahora que miro hacia atrás, no estoy seguro. Estoy extraordinariamente deprimido / exhausto, pero de cualquier manera, ¡es muy fácil parchearlo!
Estoy casi seguro de que a = wi > le ? le : widebería funcionar. De lo contrario, tienes un error.
Konrad Borowski el
a = wi>le?le:wino funcionó. Supongo que es porque estoy ejecutando git ruby ​​(desarrollador 2.2), podría haber dicho desequilibrio.
0

c ++

#define _USE_MATH_DEFINES   //so I can use M_PI
#include <math.h>           //so I can use sqrt()
#include <iostream>
#include <algorithm>

using namespace std;


int main()
{
    double w;
    double l;
    double d;
    double sd;
    double min_wl;
    double pdbd;
    double sl;
    cin >> w >> l >> d >> sd;

    min_wl = min(w, l);
    if(sd <= min_wl)
    {
        pdbd = 0.0;
    } else
    {
        pdbd = (sqrt((((sd/2)*(sd/2))-((min_wl/2)*(min_wl/2)))) + (sd/2));
    }
    sl = sd - d;

    if(sd <= min(min_wl, d))
    {
        cout << 0;
        return 0;
    } else if((sl < pdbd) && (pdbd > 0.0))    //sits on lip of box
    {
        cout << (M_PI * (((sd/2) * pdbd * pdbd) - ((pdbd * pdbd * pdbd)/(3))));
        return 0;
    } else                  //sits on bottom of box
    {
        cout << (M_PI * (((sd/2) * sl * sl)-((sl * sl * sl)/(3))));
        return 0;
    }
    return 0;
}

Mi código encuentra el volumen del sólido de rotación del gráfico de alguna parte de un semicírculo. pdbdmantiene la distancia lineal de la proyección de un punto en la superficie de la esfera que toca el borde de la caja con el diámetro de la esfera que, de extenderse, sería normal al fondo de la caja. Las dos expresiones que contienen M_PIson básicamente la anti-derivada de la integral de pi * -(x^2)+2rxcon respecto a x (donde x es una medida de la longitud a lo largo del diámetro mencionado anteriormente a través de la esfera y donde r es el radio de la esfera) evaluada en cualquiera pdbdo la diferencia del diámetro de la esfera y la profundidad de la caja según el caso particular que ocurra con las diferentes dimensiones.

usuario3142682
fuente