2015-02-12 26 views
5

वेलेंटाइन डे के रूप में देखकर तेजी से आ रहा है, मैंने दिल बनाने का फैसला किया। इसलिए मैं this heart from mathematica.se पाया:मैं इस दिल को कैसे ठीक करूं?

enter image description here

मैं Mathematica में चारों ओर खेला (जेड के लिए हल, आसपास कुछ चर स्विचिंग) दिल की z के मूल्य के लिए इस समीकरण प्राप्त करने के लिए, यह देखते हुए x और y मान (क्लिक पूर्ण आकार) के लिए:

enter image description here

मैं ईमानदारी से जावा के लिए इस समीकरण पोर्ट, एक जोड़ी के साथ काम कर बाहर के सीमा मामलों:

import static java.lang.Math.cbrt; 
import static java.lang.Math.pow; 
import static java.lang.Math.sqrt; 

... 

public static double heart(double xi, double yi) { 
    double x = xi; 
    double y = -yi; 
    double temp = 5739562800L * pow(y, 3) + 109051693200L * pow(x, 2) * pow(y, 3) 
        - 5739562800L * pow(y, 5); 
    double temp1 = -244019119519584000L * pow(y, 9) + pow(temp, 2); 
    // 
    if (temp1 < 0) { 
     return -1; // this is one possible out of bounds location 
        // this spot is the location of the problem 
    } 
    // 
    double temp2 = sqrt(temp1); 
    double temp3 = cbrt(temp + temp2); 
    if (temp3 != 0) { 
     double part1 = (36 * cbrt(2) * pow(y, 3))/temp3; 
     double part2 = 1/(10935 * cbrt(2)) * temp3; 
     double looseparts = 4.0/9 - 4.0/9 * pow(x, 2) - 4.0/9 * pow(y, 2); 
     double sqrt_body = looseparts + part1 + part2; 
     if (sqrt_body >= 0) { 
      return sqrt(sqrt_body); 
     } else { 
      return -1; // this works; returns -1 if we are outside the heart 
     } 
    } else { 
     // through trial and error, I discovered that this should 
     // be an ellipse (or that it is close enough) 
     return Math.sqrt(Math.pow(2.0/3, 2) * (1 - Math.pow(x, 2))); 
    } 
} 

केवल समस्या यह है कि जब temp1 < 0, मैं बस -1 वापस नहीं लौट सकते, जैसे मैं करता हूँ है:

if (temp1 < 0) { 
    return -1; // this is one possible out of bounds location 
       // this spot is the location of the problem 
} 

कि उस बिंदु पर दिल का व्यवहार नहीं है। यह है के रूप में, जब मैं अपने छवि बनाने की कोशिश:

import java.awt.image.BufferedImage; 
import java.io.File; 
import java.io.IOException; 
import javax.imageio.ImageIO; 

import static java.lang.Math.cbrt; 
import static java.lang.Math.pow; 
import static java.lang.Math.sqrt; 

public class Heart { 
    public static double scale(int x, int range, double l, double r) { 
     double width = r - l; 
     return (double) x/(range - 1) * width + l; 
    } 

    public static void main(String[] args) throws IOException { 
     BufferedImage img = new BufferedImage(1000, 1000, BufferedImage.TYPE_INT_RGB); 
     // this is actually larger than the max heart value 
     final double max_heart = 0.679; 
     double max = 0.0; 
     for (int x = 0; x < img.getWidth(); x++) { 
      for (int y = 0; y < img.getHeight(); y++) { 
       double xv = scale(x, img.getWidth(), -1.2, 1.2); 
       double yv = scale(y, img.getHeight(), -1.3, 1); 
       double heart = heart(xv, yv); //this isn't an accident 
       // yes I don't check for the return of -1, but still 
       // the -1 values return a nice shade of pink: 0xFFADAD 
       // None of the other values should be negative, as I did 
       // step through from -1000 to 1000 in python, and there 
       // were no negatives that were not -1 
       int r = 0xFF; 
       int gb = (int) (0xFF * (max_heart - heart)); 
       int rgb = (r << 16) | (gb << 8) | gb; 
       img.setRGB(x, y, rgb); 
      } 
     } 
     ImageIO.write(img, "png", new File("location")); 
    } 
    // heart function clipped; it belongs here 
} 

मैं इस मिल: शीर्ष पर है कि डुबकी पर

enter image description here

देखो! मैं एक .5 है कि समस्याग्रस्त -1 बदल रहा करने की कोशिश की, इस में जिसके परिणामस्वरूप:

enter image description here

अब दिल सींग है। लेकिन यह स्पष्ट हो जाता है कि समस्याग्रस्त if की स्थिति पूरी हो गई है।

मैं इस समस्या को कैसे ठीक कर सकता हूं? मैं शीर्ष पर अपने दिल में एक छेद नहीं चाहता, और मुझे एक सींग का दिल नहीं चाहिए। अगर मैं सींग को दिल के आकार में क्लिप कर सकता हूं, और बाकी को उचित रूप से रंग सकता हूं, तो यह बिल्कुल ठीक होगा। आदर्श रूप से, दिल के दोनों पक्ष एक बिंदु के रूप में एक साथ आते हैं (दिल में शामिल होने पर थोड़ा सा बिंदु होता है), लेकिन यदि वे सींग में दिखाए गए समान रूप से वक्र करते हैं, तो यह भी ठीक होगा। इसे कैसे प्राप्त किया जा सकता है?

+0

'डबल दिल = दिल (xv, yv); '- आप परिणाम की जांच नहीं कर रहे हैं> = 0 –

+0

@ लशाने मैं पूरी तरह से अवगत हूं, लेकिन -1 इसकी सीमा के लिए एक अच्छी, गुलाबी छाया उत्पन्न करता है (मुझसे मत पूछो)। यह उस समस्या को ठीक नहीं करता है जिसके बारे में मैं पूछ रहा हूं। सभी विशेष विशेषीकृत मूल्य गैर-ऋणात्मक संख्याएं उत्पन्न करते हैं (पायथन में चेक किया गया) – Justin

+4

'java.util' पर एक नज़र डालें।Timer'; एक टूटा हुआ दिल केवल समय के साथ ठीक करता है।

उत्तर

3

समस्या सरल है। अगर हम उस घोड़े की नाल क्षेत्र को देखते हैं, तो हमें काल्पनिक संख्या मिलती है। इसके हिस्से के लिए, यह हमारे दिल से संबंधित होना चाहिए। उस क्षेत्र में, अगर हम अपने कार्य का मूल्यांकन करना चाहते थे (गणित द्वारा, प्रोग्रामिंग द्वारा नहीं), फ़ंक्शन के काल्पनिक भाग रद्द हो जाते हैं। तो यह इस तरह दिखना चाहिए (मेथेमेटिका में उत्पन्न):

enter image description here

मूल रूप से, उस भाग के लिए समारोह लगभग समान है; हमें केवल वास्तविक संख्याओं के बजाय जटिल संख्याओं के साथ अंकगणित करना है।यहाँ एक समारोह है कि वास्तव में करता है:

private static double topOfHeart(double x, double y, double temp, double temp1) { 
    //complex arithmetic; each double[] is a single number 
    double[] temp3 = cbrt_complex(temp, sqrt(-temp1)); 
    double[] part1 = polar_reciprocal(temp3); 
    part1[0] *= 36 * cbrt(2) * pow(y, 3); 
    double[] part2 = temp3; 
    part2[0] /= (10935 * cbrt(2)); 
    toRect(part1, part2); 
    double looseparts = 4.0/9 - 4.0/9 * pow(x, 2) - 4.0/9 * pow(y, 2); 
    double real_part = looseparts + part1[0] + part2[0]; 
    double imag_part = part1[1] + part2[1]; 
    double[] result = sqrt_complex(real_part, imag_part); 
    toRect(result); 

    // theoretically, result[1] == 0 should work, but floating point says otherwise 
    if (Math.abs(result[1]) < 1e-5) { 
     return result[0]; 
    } 
    return -1; 
} 

/** 
* returns a specific cuberoot of this complex number, in polar form 
*/ 
public static double[] cbrt_complex(double a, double b) { 
    double r = Math.hypot(a, b); 
    double theta = Math.atan2(b, a); 
    double cbrt_r = cbrt(r); 
    double cbrt_theta = 1.0/3 * (2 * PI * Math.floor((PI - theta)/(2 * PI)) + theta); 
    return new double[]{cbrt_r, cbrt_theta}; 
} 

/** 
* returns a specific squareroot of this complex number, in polar form 
*/ 
public static double[] sqrt_complex(double a, double b) { 
    double r = Math.hypot(a, b); 
    double theta = Math.atan2(b, a); 
    double sqrt_r = Math.sqrt(r); 
    double sqrt_theta = 1.0/2 * (2 * PI * Math.floor((PI - theta)/(2 * PI)) + theta); 
    return new double[]{sqrt_r, sqrt_theta}; 
} 

public static double[] polar_reciprocal(double[] polar) { 
    return new double[]{1/polar[0], -polar[1]}; 
} 

public static void toRect(double[]... polars) { 
    for (double[] polar: polars) { 
     double a = Math.cos(polar[1]) * polar[0]; 
     double b = Math.sin(polar[1]) * polar[0]; 
     polar[0] = a; 
     polar[1] = b; 
    } 
} 

अपने कार्यक्रम के साथ इस में शामिल होने के लिए, बस अपने समारोह को बदलने इसे दर्शाने के लिए:

:

if (temp1 < 0) { 
    return topOfHeart(x, y, temp, temp1); 
} 

और यह चल रहा है, हम वांछित परिणाम प्राप्त

enter image description here


यह बहुत स्पष्ट किया जाना चाहिए कि इस नए कामकाज औजारों पर बिल्कुल वही सूत्र। लेकिन प्रत्येक भाग कैसे काम करता है?

double[] temp3 = cbrt_complex(temp, sqrt(-temp1)); 

cbrt_complexa + b i के रूप में एक जटिल संख्या लेता है। यही कारण है कि दूसरा तर्क बस sqrt(-temp1) है (ध्यान दें कि temp1 < 0, इसलिए मैं Math.abs के बजाय - का उपयोग करता हूं; Math.abs शायद एक बेहतर विचार है)। cbrt_complex ध्रुवीय रूप में जटिल संख्या के घन रूट को लौटाता है: r eWe can see from wolframalpha कि सकारात्मक r और θ साथ, हम एक जटिल संख्याओं के एक n वें जड़ इस प्रकार लिख सकते हैं:

MathJax: \sqrt[n]r\,e^{i\left(2\pi\left\lfloor\frac{\pi-\theta}{2\pi}\right\rfloor+\theta\right)}

और वह है वास्तव में कैसे cbrt_complex और sqrt_complex काम के लिए कोड। ध्यान दें कि दोनों आयताकार निर्देशांक (a + b i) में एक जटिल संख्या ले और ध्रुवीय निर्देशांक (r e)

double[] part1 = polar_reciprocal(temp3); 

यह एक आयताकार जटिल संख्या की तुलना में एक ध्रुवीय जटिल संख्या की पारस्परिक लेने के लिए आसान है में एक जटिल संख्या लौटने। अगर हमारे पास r e है, तो इसका पारस्परिक (मानक मानक नियमों का पालन करता है, सौभाग्य से) 1/r e-iθ है। यह वास्तव में हम ध्रुवीय रूप में क्यों रह रहे हैं; ध्रुवीय रूप गुणात्मक प्रकार के संचालन को आसान बनाता है, और अतिरिक्त प्रकार के संचालन कठिन होता है, जबकि आयताकार रूप विपरीत होता है।

सूचना है कि यदि हम एक ध्रुवीय जटिल संख्या r e है और हम एक वास्तविक संख्या d से गुणा करना चाहते हैं, इस सवाल का जवाब d r e के रूप में सरल है।

toRect फ़ंक्शन ठीक वही करता है जो ऐसा लगता है: यह ध्रुवीय समन्वय जटिल संख्याओं को आयताकार समन्वय जटिल संख्याओं में परिवर्तित करता है।

आपने देखा होगा कि अगर कथन यह जांच नहीं करता है कि कोई काल्पनिक हिस्सा है, लेकिन केवल तभी काल्पनिक हिस्सा वास्तव में छोटा है। ऐसा इसलिए है क्योंकि हम फ़्लोटिंग पॉइंट नंबर का उपयोग कर रहे हैं, इसलिए result[1] == 0 जांचना असफल हो जाएगा।

और वहां आप हैं! ध्यान दें कि हम वास्तव में पूरे जटिल कार्य को इस जटिल संख्या अंकगणितीय के साथ कार्यान्वित कर सकते हैं, लेकिन इससे बचने के लिए शायद तेज़ है।

संबंधित मुद्दे