Sortir des sentiers battus


16

Vous essayez d'insérer une sphère dans une boîte à 5 faces, mais parfois elle ne s'adapte pas complètement. Écrivez une fonction pour calculer la proportion de la sphère à l'extérieur (au-dessus du bord) de la boîte.

Il y a 3 situations possibles:

  • La sphère s'insère complètement dans la boîte. La réponse sera 0.
  • La sphère se trouve sur le bord de la boîte. La réponse représentera plus de la moitié du volume total.
  • La sphère se trouve au fond de la boîte.

Vous pouvez voir chaque situation ici:

Image

Vous devez écrire un programme ou une fonction pour calculer cette valeur sur au moins 4 chiffres significatifs.

Entrée: 4 nombres réels non négatifs dans le format qui vous convient * - largeur, longueur, profondeur de la boîte (mesures intérieures) et diamètre de la sphère.

Sortie: 1 nombre réel non négatif dans un format utilisable * - le volume total (pas le pourcentage) de la sphère en dehors de la boîte.

* doit être convertible en / à partir d'une chaîne décimale

Nous vous encourageons à limiter autant que possible votre utilisation de la trigonométrie.

Il s'agit d'un concours de popularité, alors sortez des sentiers battus!


des exemples, s'il vous plaît?
mniip

1
Pouvons-nous supposer que les parois de la boîte sont infiniment minces ou que les dimensions indiquées sont des dimensions intérieures? :)
Darren Stone

Quelles sont les valeurs maximales pour les entrées?
Blender

@DarrenStone Je pense que l'épaisseur des murs n'est pas importante. Vous pouvez également le considérer comme infini, de sorte que la boîte serait un trou rectangulaire dans un bloc infini. Le résultat serait le même que toute autre valeur pour l'épaisseur de paroi. Sauf si vous avez l'intention de contourner / tricher les règles en cassant physiquement, en déformant ou en tranchant la boîte ou la sphère, ou en faisant quelque chose de vraiment étrange.
Victor Stafusa

3
@DarrenStone Les boîtes ont seulement une épaisseur aux fins d'une belle image. Le problème concerne les dimensions intérieures.
Kendall Frey

Réponses:


21

Forth

Veuillez trouver ci-dessous une sphère en dehors de la boîte.

La "sphère" est la fonction de calcul du volume f. Les cas de test de référence composent la "boîte".

                     ( 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

Production:

0. 
0.523598775598299 
0.261799387799149 
0.279345334323962 
0.0654299441440212 

5

Java - basé sur un nombre entier

Ce programme n'utilise pas pi et n'appelle aucune fonction externe - pas même sqrt. Il utilise seulement arithmétique simple - +, -, *et /. De plus, outre une étape de mise à l'échelle, il fonctionne exclusivement avec des entiers. Il divise fondamentalement la sphère en petits cubes et compte ceux qui sont en dehors de la boîte.

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));
    }
}

Production:

0.0
0.5235867850933005
0.26178140856157484
0.27938608275528054
0.06542839088004015

Sous cette forme, le programme nécessite plus de 2 Go de mémoire (fonctionne -Xmx2300mici) et est assez lent. Il utilise la mémoire pour précalculer un tas de racines carrées (arithmétiquement); ce n'est pas vraiment nécessaire, mais sans cela ce serait BEAUCOUP plus lent. Pour améliorer à la fois les besoins en mémoire et la vitesse, réduisez la valeur de la MINconstante (cela diminuera cependant la précision).


2

Python 2 (approche basée sur un tableau)

Il crée un tableau de tableaux avec des valeurs de vérité si un carré spécifique dans cette grille est à l'intérieur du cercle ou à l'extérieur du cercle. Il devrait devenir plus précis plus le cercle est grand. Il sélectionne ensuite une zone en dessous ou au-dessus d'une certaine ligne et compte la quantité de carrés qui appartient au cercle et la divise par la quantité de carrés qui sont dans le cercle entier.

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)

2

Python 2.7, formule à calotte sphérique

Cette version lancera un avertissement d'exécution dans certains cas, mais affichera toujours la bonne réponse.

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))

Pour 11 caractères de plus, je peux me débarrasser de l'avertissement.

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))

Voici les cas de test exécutés sur la version 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

Même si ce n'est pas le golf de code, vous pouvez réduire import numpy as nà from numpy import*et ôtez tous les n.dans votre code.
Timtech

@Timtech Merci pour l'avertissement et la suggestion.
user2487951

1

Mathematica

Utilisation de l'intégration numérique avec des limites appropriées.

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]]]}]
  ]

0

Implémentation de référence - 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);
        }
    }
}

Production:

0
0.523598775598299
0.261799387799149
0.279345334323962
0.0654299441440212

Je ne comprends pas ces résultats. Le premier est évidemment 0. Le second n'a pas de hauteur, donc on devrait être 1. Le troisième peut loger le ballon, et exactement la moitié est au-dessus (la réponse doit être 0,5). La boîte dans le cas 4 est juste un peu petite, elle repose donc sur le dessus de la boîte. La réponse devrait être un peu plus de 0,5. La réponse pour la dernière devrait être> 0,5, car la largeur / longueur n'est pas suffisante pour rentrer la balle à l'intérieur.
Sumurai8

@ Sumurai8 "Sortie: le volume total ( pas le pourcentage ) de la sphère en dehors de la boîte."
Kendall Frey

0

Rubis

Voyons voir ...
Si la boîte est entièrement à l'intérieur, alors largeur> diamètre; longueur> diamètre et hauteur> diamètre.
Ce devrait être le premier contrôle à exécuter.

S'il est assis en bas, alors w> d; l> d et h V=(pi*h^2 /3)*(3r-h)Donc, dans ce cas, nous obtenons simplement la hauteur et la parcourons.

S'il est bloqué, nous utilisons une formule similaire ( V=(pi*h/6)*(3a^2 + h^2)). En fait, notre formule précédente est basée sur celle-ci! Essentiellement, nous utilisons cela, et a est tout simplement le plus petit de w et l. (indice, nous pouvons obtenir de la hauteur en faisant h=r-a)

Maintenant, le code!

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

Remarque ** Je ne l'ai pas trop testé, donc une erreur peut s'être glissée, si quelqu'un le remarque, dites-le!
Mais les calculs sont solides.
Version plus courte:

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)])}

(Maintenant, je sais avec certitude que l'obtention de h pour v2 se fait différemment, mais je le corrigerai plus tard.


Agréable. Ce code se lit clairement. Mais êtes-vous sûr de la déclaration suivante? "nous pouvons obtenir de la hauteur en faisant h=r-a" Je lisais simplement les formules de calotte sphérique , et le diagramme ne suggère pas une relation aussi simple. Je vais lui donner une autre lecture.
Darren Stone

@DarrenStone Maintenant que je regarde en arrière, je ne suis pas sûr. Je suis extraordinairement bas / épuisé, mais de toute façon, c'est très facile à patcher!

Je suis presque sûr que ça a = wi > le ? le : widevrait marcher. Sinon, vous avez un bug.
Konrad Borowski

a = wi>le?le:win'a pas fonctionné. Je suppose que c'est parce que j'utilise git ruby ​​(développeur 2.2), cela pourrait avoir dit un déséquilibre.

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;
}

Mon code trouve le volume du solide de rotation du graphe d'une partie d'un demi-cercle. pdbddétient la distance linéaire de la projection d'un point sur la surface de la sphère qui touche la lèvre de la boîte au diamètre de la sphère qui, si elle était étendue, serait normale au fond de la boîte. Les deux expressions qui contiennent M_PIsont fondamentalement l'anti-dérivé de l'intégrale de pi * -(x^2)+2rxpar rapport à x (où x est une mesure de la longueur le long du diamètre mentionné ci-dessus à travers la sphère et où r est le rayon de la sphère) évalué à pdbdou la différence du diamètre de la sphère et de la profondeur de la boîte en fonction du cas particulier qui se produit avec les différentes dimensions.

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.