C #, जावा और इसी तरह के गणित-उन्मुख कोड की पठनीयता में सुधार के लिए कोई क्या कर सकता है? [बन्द है]


16

C प्रोग्रामर और C # प्रोग्रामर दोनों के रूप में, C # के बारे में मुझे जो चीजें पसंद नहीं हैं, उनमें से एक क्रिया गणित के कार्य हैं। हर बार जब आप उदाहरण के लिए पाप, कोसाइन या पावर फंक्शन का उपयोग करते हैं, तो आपको मैथ स्टैटिक क्लास को प्रीपेंड करना होगा। यह बहुत लंबे कोड की ओर जाता है जब समीकरण स्वयं बहुत सरल होता है। यदि आप डेटा प्रकार टाइप करना चाहते हैं तो समस्या और भी बदतर हो जाती है। नतीजतन, मेरी राय में, पठनीयता ग्रस्त है। उदाहरण के लिए:

double x =  -Math.Cos(X) * Math.Sin(Z) + Math.Sin(X) * Math.Sin(Y) * Math.Cos(Z);

के रूप में बस का विरोध किया

double x = -cos(X) * sin(Z) + sin(X) * sin(Y) * cos(Z);

जावा की तरह अन्य भाषाओँ में भी यही स्थिति है।

मुझे यकीन नहीं है कि इस प्रश्न का वास्तव में समाधान है, लेकिन मैं यह जानना चाहूंगा कि क्या कोई कोड C # या जावा प्रोग्रामर मैथ कोड की पठनीयता में सुधार करने के लिए उपयोग करते हैं। मुझे एहसास है कि सी # / जावा / आदि। MATLAB या इसी तरह की गणित-उन्मुख भाषाएं नहीं हैं, इसलिए यह समझ में आता है। लेकिन कभी-कभी किसी को गणित कोड लिखने की आवश्यकता होती है और यह बहुत अच्छा होगा यदि कोई इसे और अधिक पठनीय बना सकता है।


मैं किसी भी विशेष रूप से नहीं जानता, लेकिन आप शायद एक बीजगणित पुस्तकालय पा सकते हैं जो आपको स्ट्रिंग के साथ गणित कार्यों को परिभाषित करने की अनुमति देगा, हालांकि कुछ प्रदर्शन जुर्माना होगा।
raptortech97


7
आप कुछ अतिरिक्त क्रियात्मकता के बारे में चिंता करते हैं, फिर भी खुशी से एक '+' को '*' में छिपाते हैं, एकतरफा ऑपरेटरों के साथ - बिना ब्रेसिज़ के - मुझे संदेह है कि आपकी प्राथमिकताएँ गलत हैं।
मटनज

1
यह सिर्फ एक उदाहरण था, लेकिन अच्छी बात
9a3eedi

6
सी # 6.0 में, आप लिखने में सक्षम हो जाएगा: using System.Math; … double x = -Cos(X) * Sin(Z) + Sin(X) * Sin(Y) * Cos(Z);
svick

जवाबों:


14

आप स्थानीय कार्यों को परिभाषित कर सकते हैं जो वैश्विक स्थिर कार्यों को कहते हैं। उम्मीद है कि कंपाइलर रैपर को इनलाइन करेगा, और फिर जेआईटी कंपाइलर वास्तविक संचालन के लिए तंग विधानसभा कोड का उत्पादन करेगा। उदाहरण के लिए:

class MathHeavy
{
    private double sin(double x) { return Math.sin(x); }
    private double cos(double x) { return Math.cos(x); }

    public double foo(double x, double y)
    {
        return sin(x) * cos(y) - cos(x) * sin(y);
    }
}

आप उन कार्यों को भी बना सकते हैं जो सामान्य गणित संचालन को एकल संचालन में बंडल करते हैं। यह उन उदाहरणों की संख्या को कम कर देगा , जहां आपके कोड में फ़ंक्शन पसंद sinऔर cosदिखाई देते हैं, जिससे वैश्विक स्थिर कार्यों को कम ध्यान देने योग्य होने का आभास होता है। उदाहरण के लिए:

public Point2D rotate2D(double angle, Point2D p)
{
    double x = p.x * Math.cos(angle) - p.y * Math.sin(angle);
    double y = p.x * Math.sin(angle) + p.y * Math.cos(angle);

    return new Point2D(x, y)
}

आप अंक और घुमाव के स्तर पर काम कर रहे हैं, और अंतर्निहित ट्रिगर फ़ंक्शन दफन हैं।


... क्यों मुझे लगता है कि :) नहीं सोचा था
9a3eedi

मैंने इसे सही उत्तर के रूप में चिह्नित किया है क्योंकि यह एक क्रॉस-प्लेटफ़ॉर्म समाधान है जो काफी सरल है। अन्य समाधान भी सही हैं। मैं वास्तव में विश्वास नहीं कर सकता कि मैंने इस बारे में सोचा नहीं था :) यह सिर्फ बहुत स्पष्ट है
9a3eedi

31

जावा के भीतर, कुछ चीजों को कम करने के लिए कई उपकरण उपलब्ध हैं, आपको बस उनके बारे में पता होना चाहिए। इस मामले में जो उपयोगी है वह staticआयात ( ट्यूटोरियल पेज , विकिपीडिया ) है।

इस मामले में,

import static java.lang.Math.*;

class Demo {
    public static void main (String[] args) {
        double X = 42.0;
        double Y = 4.0;
        double Z = PI;

        double x =  -cos(X) * sin(Z) + sin(X) * sin(Y) * cos(Z);
        System.out.println(x);
    }
}

काफी अच्छी तरह से ( ideone ) चलाता है । यह गणित वर्ग के सभी का स्थैतिक आयात करने के लिए थोड़ा भारी है , लेकिन यदि आप बहुत अधिक गणित कर रहे हैं, तो इसे बुलाया जा सकता है।

स्थैतिक आयात आपको एक स्थिर क्षेत्र या विधि को इस वर्ग के नामस्थान में आयात करने की अनुमति देता है और पैकेज नाम की आवश्यकता के बिना इसे लागू करता है। आप अक्सर इसे जूनिट परीक्षण के मामलों में पाते हैं जहां import static org.junit.Assert.*;सभी उपलब्धियां प्राप्त करने के लिए पाया जाता है।


बहुत बढ़िया जवाब। मुझे इस फीचर की जानकारी नहीं थी। जावा के किस संस्करण के तहत यह संभव है?
9a3eedi

@ 9a3eedi यह पहली बार जावा 1.5 में उपलब्ध कराया गया था।

अच्छी तकनीक है। मुझें यह पसंद है। +1।
रान्डेल कुक

1
@RandallCook जावा 1.4 दिनों में, लोग इंटरफ़ेस में स्थिरांक तक पहुंचने के लिए चीजों को पसंद करेंगे public interface Constants { final static public double PI = 3.14; }और फिर public class Foo implements Constantsसभी वर्गों में करेंगे। यह एक बना बड़ा गड़बड़। इसलिए, 1.5 के साथ, स्थिर आयात को एक इंटरफ़ेस को लागू किए बिना विशिष्ट स्थिरांक और स्थिर कार्यों में खींचने की अनुमति देने के लिए जोड़ा गया था।

3
आप चुनिंदा फ़ंक्शंस आयात कर सकते हैंimport static java.lang.Math.cos;
शाफ़्ट फ्रीक

5

C # 6.0 के साथ आप स्टैटिक इंपोर्ट की सुविधा का उपयोग कर सकते हैं।

आपका कोड हो सकता है:

using static System.Math;
using static System.Console;
namespace SomeTestApp
{
    class Program
    {
        static void Main(string[] args)
        {
            double X = 123;
            double Y = 5;
            double Z = 10;
            double x = -Cos(X) * Sin(Z) + Sin(X) * Sin(Y) * Cos(Z);
            WriteLine(x); //Without System, since it is imported 
        }
    }
}

देखें: स्टेटमेंट का उपयोग करते हुए स्टेटिक (AC # 6.0 भाषा पूर्वावलोकन)

एक और C # 6.0 "सिंटैक्टिक शुगर" सुविधा स्थैतिक का उपयोग करने की शुरूआत है। इस सुविधा के साथ, किसी स्थिर विधि को लागू करते समय एक स्पष्ट संदर्भ को समाप्त करना संभव है । इसके अलावा, स्थैतिक का उपयोग करने से आप किसी विशिष्ट वर्ग पर केवल एक्सटेंशन विधियों को प्रस्तुत कर सकते हैं, बजाय किसी नामपट के सभी एक्सटेंशन विधियों के।

EDIT: विजुअल स्टूडियो 2015 के बाद से, जनवरी 2015 में CTP जारी किया गया, स्थैतिक आयात के लिए स्पष्ट कीवर्ड की आवश्यकता है static। पसंद:

using static System.Console;

4

अन्य अच्छे उत्तरों के अलावा, मैं पर्याप्त गणितीय जटिलता (औसत उपयोग के मामले नहीं, लेकिन शायद कुछ वित्तीय या शैक्षणिक परियोजनाओं) के साथ स्थितियों के लिए एक डीएसएल की सिफारिश भी कर सकता हूं ।

Xtext जैसे DSL पीढ़ी उपकरण के साथ , आप अपने स्वयं के सरलीकृत गणितीय व्याकरण को परिभाषित कर सकते हैं, जो बदले में आपके फ़ार्मुलों के जावा (या किसी अन्य भाषा) प्रतिनिधित्व के साथ एक वर्ग उत्पन्न कर सकता है।

DSL अभिव्यक्ति:

domain GameMath {
    formula CalcLinearDistance(double): sqrt((x2 - x1)^2 + (y2 - y1)^2)
}

उत्पन्न आउटपुट:

public class GameMath {
    public static double CalcLinearDistance(int x1, int x2, int y1, int y2) {
        return Math.sqrt(Math.pow(x2 - x1, 2) + Math.pow(y2 - y1, 2));
    }
}

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


8
हां, सामान्य तौर पर, और परिभाषा के अनुसार, जब आप किसी विशिष्ट डोमेन में काम करते हैं तो एक डीएसएल उपयोगी हो सकता है। हालाँकि, यदि यह डीएसएल मौजूद नहीं है, या यदि यह आवश्यकताओं के अनुकूल नहीं है, तो आपको इसे बनाए रखना होगा, जो समस्याग्रस्त हो सकता है। इसके अलावा, विशिष्ट प्रश्न के लिए ("मैं हर बार मैथ क्लास को लिखे बिना पाप, कॉस, ... तरीके / फ़ंक्शन का उपयोग कैसे कर सकता हूं"), एक डीएसएल शायद एक बड़ा समाधान है।
मोगेनीमैन

4

C # में आप एक्सटेंशन विधियों का उपयोग कर सकते हैं।

एक बार जब आप "पोस्टफिक्स" नोटेशन के अभ्यस्त हो जाते हैं, तो नीचे बहुत अच्छी तरह से पढ़ा जाता है:

public static class DoubleMathExtensions
{
    public static double Cos(this double n)
    {
        return Math.Cos(n);
    }

    public static double Sin(this double n)
    {
        return Math.Sin(n);
    }

    ...
}

var x =  -X.Cos() * Z.Sin() + X.Sin() * Y.Sin() * Z.Cos();

दुर्भाग्य से ऑपरेटर की प्रक्रिया यहां नकारात्मक संख्याओं से निपटने के दौरान चीजों को थोड़ा बदसूरत बना देती है। यदि आप Math.Cos(-X)इसके बजाय गणना करना चाहते हैं, तो आपको -Math.Cos(X)कोष्ठक में संख्या को संलग्न करना होगा:

var x = (-X).Cos() ...

1
संयोग से, यह विस्तार गुणों के लिए एक अच्छा उपयोग मामला बना देगा, और यहां तक ​​कि तरीकों के रूप में गुणों का दुरुपयोग करने के लिए एक वैध उपयोग का मामला!
जोर्ग डब्ल्यू मित्तग

यही मैंने सोचा है। x.Sin()कुछ समायोजन होगा, लेकिन मैं विस्तार के तरीकों का दुरुपयोग करता हूं और यह व्यक्तिगत रूप से मेरा पहला झुकाव होगा।
वर्नरसीडी

2

C #: Randall Cook के उत्तर पर एक भिन्नता , जो मुझे पसंद है क्योंकि यह विस्तार विधियों की तुलना में कोड के गणितीय "लुक" को बनाए रखता है, एक आवरण का उपयोग करना है, लेकिन उन्हें लपेटने के बजाय कॉल के लिए फ़ंक्शन संदर्भ का उपयोग करें। मुझे व्यक्तिगत रूप से लगता है कि यह कोड को साफ दिखता है, लेकिन यह मूल रूप से एक ही काम कर रहा है।

मैंने रैंडल के लिपटे कार्यों, मेरे फ़ंक्शन संदर्भों और प्रत्यक्ष कॉल सहित थोड़ा LINQPad परीक्षण कार्यक्रम खटखटाया।

फ़ंक्शन संदर्भित कॉल मूल रूप से डायरेक्ट कॉल के समान समय लेती हैं। लिपटे हुए कार्य लगातार धीमे होते हैं - हालांकि एक बड़ी राशि द्वारा नहीं।

यहाँ कोड है:

void Main()
{
    MyMathyClass mmc = new MyMathyClass();

    System.Diagnostics.Stopwatch sw = System.Diagnostics.Stopwatch.StartNew();

    for(int i = 0; i < 50000000; i++)
        mmc.DoStuff(1, 2, 3);

    "Function reference:".Dump();
    sw.Elapsed.Dump();      
    sw.Restart();

    for(int i = 0; i < 50000000; i++)
        mmc.DoStuffWrapped(1, 2, 3);

    "Wrapped function:".Dump();
    sw.Elapsed.Dump();      
    sw.Restart();

    "Direct call:".Dump();
    for(int i = 0; i < 50000000; i++)
        mmc.DoStuffControl(1, 2, 3);

    sw.Elapsed.Dump();
}

public class MyMathyClass
{
    // References
    public Func<double, double> sin;
    public Func<double, double> cos;
    public Func<double, double> tan;
    // ...

    public MyMathyClass()
    {
        sin = System.Math.Sin;
        cos = System.Math.Cos;
        tan = System.Math.Tan;
        // ...
    }

    // Wrapped functions
    public double wsin(double x) { return Math.Sin(x); }
    public double wcos(double x) { return Math.Cos(x); }
    public double wtan(double x) { return Math.Tan(x); }

    // Calculation functions
    public double DoStuff(double x, double y, double z)
    {
        return sin(x) + cos(y) + tan(z);
    }

    public double DoStuffWrapped(double x, double y, double z)
    {
        return wsin(x) + wcos(y) + wtan(z);
    }

    public double DoStuffControl(double x, double y, double z)
    {
        return Math.Sin(x) + Math.Cos(y) + Math.Tan(z);
    }
}

परिणाम:

Function reference:
00:00:06.5952113

Wrapped function:
00:00:07.2570828

Direct call:
00:00:06.6396096

1

स्काला का उपयोग करें! आप प्रतीकात्मक परिचालकों को परिभाषित कर सकते हैं, और आपको अपने तरीकों के लिए परिजनों की आवश्यकता नहीं है। इस गणित में आता है जिस तरह से व्याख्या करने के लिए आसान।

उदाहरण के लिए, स्काला और जावा में समान गणना कुछ इस तरह हो सकती है:

// Scala
def angle(u: Vec, v: Vec) = (u*v) / sqrt((u*u)*(v*v))

// Java
public double angle(u: Vec, v: Vec) {
  return u.dot(v) / sqrt(u.dot(u)*v.dot(v));
}

यह बहुत जल्दी जोड़ता है।


2
सीएलआर, केवल जेवीएम पर स्कैला उपलब्ध नहीं है। इस प्रकार यह वास्तव में C # के लिए एक व्यवहार्य विकल्प नहीं है।
बेन रडर्स

@benrudgers - C # JVM पर नहीं चलता है, इसलिए यह वास्तव में जावा के लिए एक व्यवहार्य विकल्प नहीं है, जिसके बारे में सवाल पूछा गया था। सवाल यह निर्दिष्ट नहीं करता है कि यह सीएलआर होना चाहिए!
रेक्स केर

हो सकता है कि मैं लुडाइट हूं, लेकिन "*" के बजाय "डॉट" के लिए दो अतिरिक्त वर्ण, इस लाभ के साथ कि कोड स्पष्ट है, भुगतान करने के लिए एक छोटी सी कीमत लगती है। फिर भी, एक अच्छा जवाब।
user949300
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.