Страницы

Поиск по вопросам

Показаны сообщения с ярлыком методы. Показать все сообщения
Показаны сообщения с ярлыком методы. Показать все сообщения

вторник, 31 марта 2020 г.

Разные перегрузки универсального метода в зависимости от указанного типа

#c_sharp #generics #методы


товарищи! Наткнулся я тут на старенькое интеревью с Джоном Скитом на хабре. В его
рамках Джон задал читателям следующий вопрос: 


  Как вы можете заставить этот код скомпилироваться, так чтобы он вызвал
  три различные перегрузки метода?


void Foo()
{
    EvilMethod();
    EvilMethod();
    EvilMethod();
}


Мне не совсем понятно, как можно реализовать такую вещь, ведь даже если использовать
where, то мы получаем ошибку, что метод с таким же названием и параметрами уже существует.
На SO искал, в Google тоже (возможно, искал плохо, так что если что - палками не бейте))
Будет очень интересно выслушать ваши идеи, так что заранее спасибо)
    


Ответы

Ответ 1



Удалось сделать только так: public interface IEvilMethod { void EvilMethod(); } public class Example : IEvilMethod, IEvilMethod, IEvilMethod { public void Foo() { ((IEvilMethod) this).EvilMethod(); ((IEvilMethod) this).EvilMethod(); ((IEvilMethod) this).EvilMethod(); } void IEvilMethod.EvilMethod() { Console.WriteLine(typeof(T)); } void IEvilMethod.EvilMethod() { Console.WriteLine(typeof(T)); } void IEvilMethod.EvilMethod() { Console.WriteLine(typeof(T)); } } Update Нашел решение здесь. public class ReferenceGeneric where T : class { } public class EvilClassBase { protected void EvilMethod() { Console.WriteLine("int?"); } } public class EvilClass : EvilClassBase { public void Run() { EvilMethod(); EvilMethod(); EvilMethod(); } private void EvilMethod(ReferenceGeneric arg = null) where T : class { Console.WriteLine("string"); } private void EvilMethod(T? arg = null) where T : struct { Console.WriteLine("int"); } }

пятница, 14 февраля 2020 г.

Использование шаблонов для указания имен методов

#cpp #классы #шаблоны_с++ #методы


Подскажите как более правильно и красиво реализовать следующую задумку:

Есть некоторый класс CTasksManager, у которого есть публичный метод CTasksManager::start,
который подготавливает данные и запускает потоки, в каждом из которых используется
приватный метод methodN (method1, method2, ..., methodN).

Иногда мне требуется, чтобы start работал с одним методом, иногда с другим. Но всегда
с одним и тем же в процессе выполнения программы (т.е. не динамический выбор метода).

Заходить в нужный файл и править один вызов на другой - это некрасиво и вообще детский
сад :), поэтому мне кажется, что лучшее решение - использование шаблонов, например так:

class CTasksManager
{
private:
    void method1();
    void method2();

public:
    void start();
};


Т.е. чтобы вызовы можно было бы делать так:

CTasksManager tasksManager;

tasksManager.start();
...
tasksManager.start();


Можно ли это реализовать силами стандартного C++ (без буста) и если да, то как?
Может есть более правильный способ? 
    


Ответы

Ответ 1



Для этого можно обойтись без шаблонов, передавая указатель на метод (причем метод должен стать публичным): class CTasksManager { public: void method1(); void method2(); using t_PointerToMethod = void ( CTasksManager::* )(void); void start(t_PointerToMethod const p_method) { return (this->*p_method)(); } }; tasksManager.start(&CTasksManager::method1);

Ответ 2



Вам нужно нечто похожее на std::launch. Посмотрите, как используется данное перечисление с std::async.

четверг, 13 февраля 2020 г.

Может ли базовый класс знать что-то про методы потомков?

#python #наследование #методы


Разбираюсь сейчас с наследованием в Python, а также с магическими методами. Имеется код:

class Researcher:
    def __getattr__(self, name):
        return 'Nothing found :()\n'

    def __getattribute__(self, name):
        print('Looking for {}'.format(name))
        return super().__getattribute__(name)


obj = Researcher()

print(obj.attr)
print(obj.method)
print(obj.DFG2H3J00KLL)


Возник вопрос: откуда объект object() (который создался после вызова super()) знает
о методе __getattr__ класса Researcher? Разве базовый класс знает что-то про методы
потомков?
    


Ответы

Ответ 1



super() вовсе не возвращает просто объект родительского класса. В этом легко убедиться, если перед строчкой где вы его вызываете поставить print(super()). Если такое проделать, то код в этом месте выведет: , > Как видите, это не экземпляр родительского класса object. Это особый объект-обёртка, который управляет вызовом методов из классов выше по иерархии для текущего объекта. И вот эта обёртка и знает всё и про методы Researcher, и про всех его родителей. UPD: Действительно, как правильно отметил автор вопроса в комментариях, если заменить super() на object(), то код всё равно работает. Но это уже не связано с наследованием, а связано с нюансами работы __getattr__ и __getattribute__ Дело в том, что __getattribute__, если он реализован, то он срабатывает для вообще всех обращений к атрибутам - как к существующим, так и к несуществующим. В то время, как __getattr__ срабатывает только для обращения к несуществующим атрибутам - то есть тогда, когда при обращении к атрибуту произошло исключение AttributeError. То есть вот что происходит, когда вы меняете super на object: Код делает обращение к атрибуту объекта. Так как это объект класса Researcher, для которого есть метод __getattribute__, то код выполняет именно этот метод. Внутри него идёт обращение к object().__getattribute__(name) Для экземпляра класса object обращение к аттрибуту работает стандартно, то есть для неизвестного аттрибута, такого как DFG2H3J00KLL будет выброшено исключение AttributeError Т.к. при возникновении этого исключение всегда проверяется, есть ли у объекта __getattr__, и так как всё это происходит всё ещё для экземпляра Researcher, а у него этот метод есть, то именно он и срабатывает. Проиллюстрировать это можно следующими примерами. Демонстрация того, что исключение AttributeError действительно выбрасывается: class Researcher: def __getattr__(self, name): return 'Nothing found :()\n' def __getattribute__(self, name): print('Looking for {}'.format(name)) try: object().__getattribute__(name) except Exception as e: print('!!! ', type(e)) obj = Researcher() print(obj.attr) print(obj.method) print(obj.DFG2H3J00KLL) Демонстрация того, что даже если мы не будем обращаться ни к object, ни к super, а просто руками выбросим AttributeError, то всё будет работать так же, как и изначально: class Researcher: def __getattr__(self, name): return 'Nothing found :()\n' def __getattribute__(self, name): print('Looking for {}'.format(name)) raise AttributeError obj = Researcher() print(obj.attr) print(obj.method) print(obj.DFG2H3J00KLL)

Вернуть реализующийся интерфейс IEnumerable<T> через метод, C#

#c_sharp #ссылки #интерфейс #методы


Добрый день, очень сильно плаваю в теме про обобщенные интерфейсы, методы. Был бы
весьма благодарен за подсказку, либо за ссылки, в каком направлении следует копать,
читать. Теорию прочитал с сайта professorweb.ru про интерфейсы, обобщение. Теория теорией,
что то понял, чего то нет, но на практике все равно не могу реализовать следующую задачку.

К примеру, имеется код:

DataPerson dataPerson;
IEnumerable person = dataPerson.>Get(); 
// как я понял, метод Get() должен в person записать значение ссылочного типа 
// на реализующий интерфейс типа Person? Не представляю как реализовать это.
// В плане непонятны мне следующие вопросы: 

// 1. Где следует реализовать этот интерфейс? 

// 2. Не понимаю про двойное обобщение вида >,
// а именно каким образом это указать в методе Get()?

// 3. Не понимаю как вернуть интерфейс через метод.


Класс Person:

class Person 
{
    public string FirstName { get; set; }
    public string LastName { get; set; }

    public Person(string fName, string lName)
    {
        FirstName = fName;
        LastName = lName;
    }
}


Класс DataPerson:

class DataPerson
{
    // как я примерно представляю объявление функции Get()
    public IEnumerable Get() 
        where T : IEnumerable 
    {
        // как реализовать, к сожалению не представляю
    }   
}


Как собственно реализовать метод Get() в классе DataPerson?
    


Ответы

Ответ 1



Ваш метод скорее всего должен быть объявлен как class DataPerson { public IEnumerable Get() where T : new() { } } т.к. реально у него всего один тип-параметр - тип выбираемых объектов. и использоваться как IEnumerable person = dataPersonGet(); Реализовать его можно двумя способами: Действительно создать что-то, что реализует интерфейс IEnumerable. Например, массив или список. Заполнить его и вернуть из метода: class DataPerson { public IEnumerable Get() where T : new() { var query = buildSomeQueryFor(typeof(T)); // построить запрос для выбора объектов типа T DataRow[] dataRows = selectSomeRowsFromDB(query); // var result = new List(); foreach (var row in dataRows) { result.Add(MapDataRowTo(row)); } return result; } private MapDataRowTo(DataRow row) where T : new () { var newObject = new T(); // map values from row to newObject // return return newObject; } } Второй способо - использовать ключевое слово yield: class DataPerson { public IEnumerable Get() where T : new() { var query = buildSomeQueryFor(typeof(T)); // построить запрос для выбора объектов типа T DataRow[] dataRows = selectSomeRowsFromDB(query); // foreach (var row in dataRows) { yield return MapDataRowTo(row); } } private MapDataRowTo(DataRow row) where T : new () { var newObject = new T(); // map values from row to newObject // return return newObject; } } Использование yield завернет ваш метов в обертку-IEnumerable, которая будет возвращать элементы по мере обращения к ним из вызывающего кода. Т.е. выполнение метода Get будет происходить кусками, от одного вызова yield к следующему. В MSDN есть достаточно подробная документация по этой фиче языка.

Ответ 2



Как собственно реализовать метод Get() в классе DataPerson? class DataPerson { public IEnumerable Get() { return new List() { new Person(), new Person() }; } // или так public IEnumerable Get() { return new[] { new Person(), new Person() }; } }

понедельник, 10 февраля 2020 г.

Переопределение метода экземпляра класса

#java #классы #методы


Мне нужно переопределить метод класса Button

public class Button { 
    public void action(){} 
}


Я пробовал инициализировать так:

Button home = new Button(){
    public void action() {
        // TODO some code
    }
}


Но ничего не получилось. Нужна помощь.
    


Ответы

Ответ 1



Но ничего не получилось. А в чем заключается это «не получилось»? Если при вызове переопределенного метода Вы получаете cannot resolve method, то, может быть, Вы импортировали вовсе не Ваш класс Button, а одноименный класс из другого пакета, который данного метода не имеет? При создании экземпляра некоторого класса Вы можете переопределить его методы, в итоге получите анонимный класс (а точнее, субкласс). Пример: class Button { public void action() { System.out.println("Basic implementation"); } } public class Main { public static void main(String[] args) { Button button = new Button() { @Override public void action() { System.out.println("Overridden implementation"); } }; button.action(); } } Вывод на консоль: Overridden implementation Если же класс с переопределенными методами будет использован многократно, то целесообразно создать именованный класс.

Ответ 2



Наследование никто не отменял. public class MyButton extends Button { @Override public void action(){ // переопределённая логика тут } } Button home = new MyButton();

Ответ 3



Вижу 3 способа решить проблему: 1) Классический способ через переопределение - как указано в ответе коллег по цеху (например @АндрейБогатов) 2) Через переопределение слушателя action() (очевидно, класс Button должен иметь слушателя что-то типа setOnActionListener() с соответствующим интерфейсом OnActionListener) - к сожалению ТС не дал ссылку на оригинальный класс Button - иначе я бы написал пример 3) Путь героя - написать собственный ClassLoader, который в рантайме загружает нужный class, что то типа (но это уже мозговой вывих, который применяется крайне редко): class MyClassLoader extends ClassLoader { public Class findClass(String name) { byte[] b = loadClassData(name); return defineClass(...); } private byte[] loadClassData(String name) { // загрузчик класса в вашей имплементации . . . } }

воскресенье, 9 февраля 2020 г.

Зачем нужно пробрасывать исключения?

#java #исключения #методы #обработка_ошибок


Зачем нужно пробрасывать исключения? Почему может быть нельзя из сразу обработать?
    


Ответы

Ответ 1



Чтобы обрабатывать ошибки централизованно. Вот допустим у Вас есть процесс, который разбирает определенные файлы и кладет их в базу данных. Файлы большие и сложные, поэтому логика разбита по сотне-другой классов, в каждом из которых по несколько методов. Драйвер базы данных предусматривает, что база может оказаться недоступна и все методы, которые работают с БД выбрасывают DatabaseKaputException. Т.к. разработчики драйвера фанатики, с садисткими наклонностями DatabaseKaputException — проверяемое исключение. Теперь, если все исключения обрабатывать на месте, то каждый метод, работающий с БД будет содержать try/catch: public Result someMethod() { try{ //получаем результат из БД } catch(DatabaseException de) { //а вдруг база упала? } } Проблема с таким подходом в том, что «низовые» классы понятия не имеют, что им делать если база умерла. В этом случае нужно перейти к самому верхнему классу и останавливать весь процесс. Поэтому если исключения не пробрасывать, то каждый метод должен будет определять какой-то код ошибки и передавать его вверх. public ResultWithException someMethod() { ResultWithException result; try{ //нормальный код result.setValue(...); } catch(DatabaseException de) { //Обрабатываем, возвращаем результат с ошибкой result.setError(...); } } И при каждом вызове метода нужно будет проверять не оборвался ли он: ResultWithException result = someObj.someMethod(); //а ты точно выполнился? if(result.getError()==null) { //передаем сообщение об ошибке наверх } В результате получится тот же механизм пробрасывания исключений, только самописный и более многословный. Пробрасывание позволяет обрабатывать исключение в том классе, который может принять адекватное решение по ошибке. При этом такого класса может и не быть. Если приложение работает с БД напрямую, то не всегда оправданно писать для него удобную систему обработки ошибок подключения. В таком случае исключение можно пробросить на самый верх. В принципе есть языки программирования (C, Rust) которые обрабатывают ошибки в основном через возвращаемые значения (коды ошибок, специальные типы). В Java для этого как правило используются исключения. Проверяемые исключения как раз и являются попыткой обязать разработчиков обрабатывать ошибки.

суббота, 8 февраля 2020 г.

Реализация в Java сигнатуры метода?

#java #методы


Как этот метод реализовать на java. 
Нужен для того чтобы проверить кодировку файлов на битовом уровне.
Код:
unc ::IsUTF8(unc *cpt) { if (!cpt) return 0;

if ((*cpt & 0xF8) == 0xF0) { // start of 4-byte sequence
    if (((*(cpt + 1) & 0xC0) == 0x80)
     && ((*(cpt + 2) & 0xC0) == 0x80)
     && ((*(cpt + 3) & 0xC0) == 0x80))
        return 4;
}
else if ((*cpt & 0xF0) == 0xE0) { // start of 3-byte sequence
    if (((*(cpt + 1) & 0xC0) == 0x80)
     && ((*(cpt + 2) & 0xC0) == 0x80))
        return 3;
}
else if ((*cpt & 0xE0) == 0xC0) { // start of 2-byte sequence
    if ((*(cpt + 1) & 0xC0) == 0x80)
        return 2;
}
return 0;
}

Вопрос:


Как трансформировать этот метод в
   Java code?
    


Ответы

Ответ 1



постарался максимально облегчить вашу задачу: // на счет значения не уверен, подставьте нужное private static final int UTF8_HEADER_SIZE = 8 ; public static boolean isUTF8 (String path) { return isUTF8(new File(path)) ; } public static boolean isUTF8 ( File file ) { // validate input if (null == file) { throw new IllegalArgumentException ("input file can't be null"); } if (file.isDirectory ()) { throw new IllegalArgumentException ("input file refers to a directory"); } // read input file byte [] buffer = new byte[UTF8_HEADER_SIZE]; try { readBytes(file, buffer) ; } catch ( IOException e ) { throw new IllegalArgumentException ("Can't read input file, error = " + e.getLocalizedMessage () ); } // validate file header // TODO: your validation goes here // if (0xF0 == (buffer[0] & 0xF8) ) { // } return false ; } private static void readBytes ( File input, byte[] buffer ) throws IOException { if (null == buffer || 0 == buffer.length) { return; } // read data FileInputStream fis = new FileInputStream ( input ) ; fis.read ( buffer ) ; fis.close (); }

Ответ 2



Смотрите. Для массивов в Java используется класс ArrayList. Битовые операции те же, только для беззнакового сдвига влево используется >>> (но вам это не нужно). Вместо адресной арифметики применяйте индексирование. Передать что-то типа указателя в середину массива невозможно, просто передавайте массив и начальный индекс. Сигнатура: // внутри класса public static int IsUTF8(ArrayList cpt, int startIndex) { // ... Дальше сами :-)

Ответ 3



После непростого поиска, результат (сын ошибок трудных :) ) проверки кодировки UTF-8: class EncodingsCheck implements Checker { @Override public boolean check(File currentFile) { return isUTF8(currentFile); } public static boolean isUTF8(File file) { // validate input if (null == file) { throw new IllegalArgumentException("input file can't be null"); } if (file.isDirectory()) { throw new IllegalArgumentException( "input file refers to a directory"); } // read input file byte[] buffer; try { buffer = readUTFHeaderBytes(file); } catch (IOException e) { throw new IllegalArgumentException( "Can't read input file, error = " + e.getLocalizedMessage()); } if (0 == (buffer[0] & 0x80)) { return true; // ASCII subset character, fast path } else if (0xF0 == (buffer[0] & 0xF8)) { // start of 4-byte sequence if (buffer[3] >= buffer.length) { return false; } if ((0x80 == (buffer[1] & 0xC0)) && (0x80 == (buffer[2] & 0xC0)) && (0x80 == (buffer[3] & 0xC0))) return true; } else if (0xE0 == (buffer[0] & 0xF0)) { // start of 3-byte sequence if (buffer[2] >= buffer.length) { return false; } if ((0x80 == (buffer[1] & 0xC0)) && (0x80 == (buffer[2] & 0xC0))) { return true; } } else if (0xC0 == (buffer[0] & 0xE0)) { // start of 2-byte sequence if (buffer[1] >= buffer.length) { return false; } if (0x80 == (buffer[1] & 0xC0)) { return true; } } return false; } private static byte[] readUTFHeaderBytes(File input) throws IOException { // read data FileInputStream fileInputStream = new FileInputStream(input); try{ byte firstBytes[] = new byte[4]; int count = fileInputStream.read(firstBytes); if(count < 4){ throw new IOException("Empty file"); } return firstBytes; } finally { fileInputStream.close(); } } }

вторник, 28 января 2020 г.

В чем отличие троеточия от квадратных скобок?

#java #методы #varargs


В чем разница между

private void onProgressUpdate(String... item);


и

private void onProgressUpdate(String[] item);

    


Ответы

Ответ 1



Главное отличие в сигнатуре методов. В первом случае сигнатура метода определяет один или более параметров типа String, во втором передается только один параметр типа String[]. Определение vararg также допускает использование массива в качестве аргумента. В первом случае может быть использовано onProgressUpdate("item1","item2","item3"); или onProgressUpdate(new String[]{"item1","item2","item3"}); а во втором случае только последний вариант. Более подробно об vararg можно почитать здесь.

Ответ 2



Первое, это varargs, что обозначает передачу неограниченного количества элементов. Пример: link void func(int... numbers); func(1,2,3,4,5,6,7,8); Второй, это просто передача массива. Пример: void func(int[] arr); int[] arr = new int[10]; func(arr);

Проблемы с созданием метода для класса

#классы #java #методы


Здравствуйте! Начал осваивать ООП и столкнулся с проблемой, решил написать класс
matematik и несколько методов в нем. Первым стал возведение в степень. Вот код:
public class matematik {
  public int result;
  public int erection (int a, int n) {
      if (n>0) {
        for(int i = 1; i <= n; i++) {
            result = 1;
            result = result * a;
        }
      return result;
    }
      if (n<0){
          for(int i = n; i <= 1; i++){
              result = 1;
              result = result/a;
          }
        return result;
      }
  }
}

Эклипс ругается на вот эту строчку "public int erection (int a, int n)" 

This method must return a result of type int.

Подскажите новичку, что я делаю не так?    


Ответы

Ответ 1



// matematik - неправильно, правильно mathematic. // а кроме того в java принято называть классы с заглавной class Mathematic { // есть смысл сделать метод статичным, // - т.к. его выполнение не повлияет на состояние класса public static int power(int base, int power) { // эта переменная не может быть полем // потому что нет смысла хранить временные данные за пределами данного // метода int result = 0; if (power > 0) { for (int i = 1; i <= power; i++) { result = 1; result = result * base; } // мы в любом случае будем возвращать результат // посему именно здесь можно не возвращать результат // return result; } else if (power < 0) { // чутье подсказывает что этот код работает неправильно for (int i = power; i <= 1; i++) { result = 1; result = result / base; } // мы в любом случае будем возвращать результат // посему именно здесь можно не возвращать результат // return result; } // результат возвращаем в любом случае return result; } } имеет смысл рассмотреть частные случаи: 1) степень равна 0 2) степень равна 1 3) степень меньше 0 4) степень - дробное число последний частный случай подразумевает что у вас степень может быть не только целочисленным значением, но еще и дробным. а посему лучше поменять тип данных int на double, но не думаю что есть смысл рассматривать этот вариант, т.к. его реализация не так уж проста. с другой стороны возможность задания негативной степени показывает что на входе функции может быть дробное число (5^-2 = 1/5^2 = 1/25). код учитывая все вышесказанное: public static double power(double base, int power) { // сначала обрабатываем частные случаи // это нужно чтоб наш код не делал лишних действий // возведение 0 в любую степень даст 0 // в случае когда степень будет отрицательной // придется делить на 0 if (0 == base) { return 0; } // если степень равна единице, то выполнять возведение бесполезно // if (1.0 == power) { - неправильно (1.0 имеет тип double) // спасибо @avp что заметил, так будет правильно if (1 == power) { return base; } // если степень отрицательная: то 2^(-3) = 1/(2^3) if (0 > power) { return power(1 / base, -power); } // будет хранить результат в этой переменой double result = base; // само вычисление for (int i = 1; i < power; i++) { result = result * base; } return result; }

Ответ 2



Надо перед 2 с конца скобки добавить return null;

Как избежать определения двух методов/конструкторов с одинаковыми параметрами?

#java #методы #конструктор #полиморфизм


Например, пишу класс Vector. Вполне естественно создавать объект, принимая в конструктор
или координаты x и y, или же принимая длину вектора и угол между направлением вектора
и положительным направлением оси OX. Однако я не могу написать так:

public class Vector {
    float x;
    float y;

    public Vector(float x, float y) {
        this.x = x;
        this.y = y;
    }

    public Vector(float length, float alpha) {
        this.x = length*Math.cos(alpha);
        this.y = length*Math.sin(alpha);
    }
}


Компилятор, конечно, будет ругаться на неоднозначность в определении конструкторов.
Я не могу её избежать переставив аргументы местами, так как они одинаковых типов. Что
делать в таких ситуациях, когда метод/конструктор должен принимать два разных по смыслу
набора параметров, но получается так, что они имеют одинаковые типы?
    


Ответы

Ответ 1



В таких случаях не лишним будет использование статических фабричных методов. С использованием этого шаблона ваш код будет выглядить так: public static class Vector { public final float x; public final float y; private Vector(float x, float y) { this.x = x; this.y = y; } public static Vector coordinate(float x, float y) { return new Vector(x, y); } public static Vector radian(float length, float alpha) { return new Vector(length * Math.cos(alpha), length * Math.sin(alpha);) } } Так же, можно воспользоваться шаблоном проектирования builder. Здесь он выглядит немного громоздко, но в принципе, тоже применим: public static class Vector { ... public static VectorBuilder builder() { return new VectorBuilder(); } public static class VectorBuilder { private double length; private double alpha; private float x; private float y; public VectorBuilder setLength(float length) { this.length = length; compute(); return this; } public VectorBuilder setAlpha(float alpha) { this.alpha = alpha; compute(); return this; } private void compute() { this.x = (float) (length * Math.cos(alpha)); this.y = (float) (length * Math.sin(alpha)); } public VectorBuilder setX(float x) { this.x = x; return this; } public VectorBuilder setY(float y) { this.y = y; return this; } public Vector build() { return new Vector(x, y); } } }

Ответ 2



Что-то вроде фабрики: interface SomeInterface { float setX(float x, float y); float setY(float x, float y); } class Vector { float x; float y; static SomeInterface case1 = new SomeInterface() { @Override public float setX(float x, float y) { return x; } @Override public float setY(float x, float y) { return y; } }; static SomeInterface case2 = new SomeInterface() { @Override public float setX(float x, float y) { return x * (float) Math.cos(y); } @Override public float setY(float x, float y) { return x * (float) Math.sin(y); } }; public Vector(float x, float y, SomeInterface someInterface) { this.x = someInterface.setX(x,y); this.y = someInterface.setY(x,y); } } . . . new Vector(1.0f, 2.0f, Vector.case1); new Vector(1.0f, 2.0f, Vector.case2);

Ответ 3



Можете добавить костыль в виде третьего параметра и оставить один конструктор: public Vector(float a, float b, boolean isCoordinates) { if (isCoordinates) { this.x = a; this.y = b; } else { this.x = a*Math.cos(b); this.y = a*Math.sin(b); } }

Ответ 4



Может так? public class Vector { float x; float y; public Vector(float[] ху) { this.x = ху[0]; this.y = ху[1]; } public Vector(float length, float alpha) { this.x = length*Math.cos(alpha); this.y = length*Math.sin(alpha); } }

воскресенье, 26 января 2020 г.

Как отличить переменную от метода в С#?

#c_sharp #переменные #методы


Изучаю основы. Вычисление объема сферы, фрагмент кода.

public double sqrSphere()
{
    return 4 * Math.PI * r * r;
}

public void writeResult()
{
    Console.WriteLine("Вычислить площадь или объем? s/v:");
    s = Console.ReadLine();
    s = s.ToLower();
    if (s == "s")
    {
        Console.WriteLine("Площадь шара равна {0:#.###}", sqrSphere());
        return;
    }
}


Вопросы:

public double sqrSphere() 


sqrSphere() это метод или переменная? Если метод, то как можно сделать такой вывод?
По наличию параметров после идентефикатора? Раньше знал о переменных double, а здесь
это часть метода?

Console.WriteLine("Площадь шара равна {0:#.###}", sqrSphere());


Здесь выводится значение sqrSphere() . Получается, sqrSphere() - переменная?
Совсем запутался, простите нуба.

P.S.  Всем спасибо за ответы. Есть недостаток знаний о возвращаемых типах и методах
в целом, постигаю азы.
    


Ответы

Ответ 1



Любой метод имеет сигнатуру (собственное имя + список формальных параметров), тип возвращаемого значения, а так же возможно и различные модификаторы. public double sqrSphere() - открытый метод без параметров, возвращающий значение типа double. В этой строке Console.WriteLine("Площадь шара равна {0:#.###}", sqrSphere()); сначала вычисляется результат выполнения метода, а потом этот результат подставляется в форматную строку. За ходом исполнения программы вы можете наблюдать в отладчике.

Ответ 2



небольшое дополнение к уже имеющимся правильным ответам. Действительно иногда бывает трудно только по внешнему виду отличить переменную от свойства, метода или даже типа. Особенно если код чужой, мудреный и открыт в блокноте без подсветки синтаксиса. Поэтому соглашения об именовании становятся еще более актуальными. Понятно что почти у каждой команды есть свои соглашения (camelCase, PascalCase, венгерская нотация и т.д. останется за кадром, религиозные вопросы не трогаю принципиально =)), но некоторые из них можно считать общепринятыми. Ниже примерный список таких соглашений для пользовательских идентификаторов: длина имени должна быть необходимой и достаточной для однозначного понимания его смысла. Иначе говоря, не экономьте символы в ущерб понятности названия, но и не растекайтесь мыслью. Если есть общепринятая (или принятая в вашей команде) аббревиатура (usb, wcf и т.д.), ее можно и нужно использовать, но изобретать что-то свое только для уменьшения длины имени не стоит без крайней необходимости. имя поля или свойства является существительным простым Length, Size либо составным (да простят меня лингвисты за излишнее упрощение) CurrentTime, CustomerList. Для логических полей и свойств допустимо использовать вопросительную форму (IsActive, HasValue). имя метода является глаголом Count(), Sort() или начинается с глагола GetValue(), PerformAction(). Даже этих простых правил именования, не вдаваясь в прочие аспекты Code Conventions, будет вполне достаточно, чтобы относительно комфортно читать код не разыскивая объявление сущности для опознания каждого нового идентификатора.

Ответ 3



Как выглядит разница: //Метод public double Var1() { return 0; } //Свойство public double Var2 { get { return _var3; } set { _var3 = value; } } //Переменная / поле public double _var3 = 0; Раньше знал о переменных double, а здесь это часть метода? В данном случае это не часть метода, а тип возвращаемого значения этим методом. А иногда бывает так: public double sqrSphere() { return 4 * Math.PI * r * r; } public void Print (string str, Func func) { Console.WriteLine(str, func()); } public void writeResult() { Console.WriteLine("Вычислить площадь или объем? s/v:"); s = Console.ReadLine(); s = s.ToLower(); if (s == "s") { Print("Площадь шара равна {0:#.###}", sqrSphere); return; } } Немного глупый пример на коленке, но тут можно увидеть что метод sqrSphere в метод Print передается по виду совсем как переменная/поле/метод и для того, что бы выяснить что перед нами нужно знать сигнатуру метода Print и все станет ясно.

Ответ 4



Ну и совсем уж простейшая деталь: метод без "()" не вызвать. Если видишь имя без "()" - значит, это поле. public double sqrSphere() - а если анализировать эту строку, то public - идентификатор доступа, double - тип, возвращаемый методом, sqrSphere - имя метода. Ну и "()" для принимаемых аргументов.

Ответ 5



Может быть будет понятнее то что в IL коде получается при выводе строчки в консоль? IL_0029: ldstr "Площадь шара равна {0:#.###}" IL_002e: call float64 YourNameSpace.YourClass::'sqrSphere'() IL_0033: box [mscorlib]System.Double IL_0038: call void [mscorlib]System.Console::WriteLine(string, object) call говорит о том что это вызов метода. для переменных только загрузка (команды начинающиеся с ld)

Метод в C#, меняющий местами значения переменных

#c_sharp #алгоритм #методы


Я новичок в программировании на C#, попался вопрос про обмен значениями переменных
без использования третьей. С одним из решений все понятно:

int a = 2; 
int b = 4;
a = a + b;
b = a - b;
a = a - b;


У меня другой вопрос, можно ли это как-то засунуть в метод? Написал так:

class Program
{
    public static void Main(string[] args)
    {

        Console.WriteLine("Введите значения переменных a и b");
        Console.Write("a = ");

        int x = int.Parse(Console.ReadLine());

        Console.Write("b = ");

        int y = int.Parse(Console.ReadLine());

        SwapNumbers(x, y);
        Console.Write($"Переменная a = {x}, переменная b = {y} ");
        Console.ReadLine();


    }

    public static void SwapNumbers(int a, int b)
    {
        a = a + b;
        b = a - b;
        a = a - b;
    }            
}


Но переменные x и y не меняются местами, по крайне мере в методе Main. Можно сделать так:

public static void SwapNumbers(int a, int b)
    {
        a = a + b;
        b = a - b;
        a = a - b;
        Console.Write($"Переменная a = {a}, переменная b = {b} ");
    }


Но это выглядит как-то коряво и неуместно, потому что я хочу, чтобы метод только
менял местами введенные с клавиатуры значения, а где и когда их вывести я хочу решать сам.
    


Ответы

Ответ 1



Всё дело в том, что ты передаешь копии переменных в метод Swap. Чтобы иметь возможность передавать ссылку есть ключевое слово ref. Т.е. метод будет выглядеть так: public static void Main(string[] args) { int a = 7, b = 5; Console.WriteLine("a -> {0}; b -> {1}", a, b); Swap(ref a, ref b); Console.WriteLine("a -> {0}; b -> {1}", a, b); } public static void Swap(ref int a, ref int b) { a = a + b; b = a - b; a = a - b; } Есть также параметр out. Разница между ref и out тут: ref и out

Ответ 2



Если использовать крайнюю версию языка C#, то можно вытворять вот такой беспредел int a = 10; int b = 15; Console.WriteLine($"{a}-{b}"); (a, b) = (b, a); // обмен Console.WriteLine($"{a}-{b}"); вывод ожидаемо 10-15 15-10

Ответ 3



При передаче в метод по значению (по умолчанию) в метод передается копия переменной, соответственно в вашем коде значения x и y не изменяются. При указании модификатора ref переменные передаются в метод по ссылке, а не по значению. В этом случае при изменении значений переменной в методе будет изменено значение и в вызывающем методе.

Ответ 4



void Swap(ref T a, ref T b){ T temp = a; a = b; b = temp; //Здесь означает что будут использоваться неконкретные типы и мы эти типы и //будем менять местами. При вызове метода нужно использовать такой синтаксис //int a = 0, b = 1; //Swap(ref a,ref b) } Можно в острые скобки (не знаю как их принято называть) вписываем тип переменной и всё.

воскресенье, 12 января 2020 г.

Динамическое добавление методов к объекту в Python 3

#python #python_3x #классы #методы


Допустим у меня есть класс

class A:
    x, y = 1, 2


и объект для этого класса

a = A()


Как добавить к a новый метод?

Если сделать так

a.f = lambda self: self.x + self.y
print(a.f())


то получаю ошибку

Traceback (most recent call last):
  File "python", line 8, in 
TypeError: () missing 1 required positional argument: 'self'


А если так

a.f = lambda: "body"


то внутри лямбда функции у меня нет доступа к объекту.
    


Ответы

Ответ 1



https://stackoverflow.com/questions/972/adding-a-method-to-an-existing-object-instance import types class A: x, y = 1, 2 a = A() a.f = types.MethodType(lambda self: self.x + self.y, a) a.f() # --> 3 Разница в следующем: a.g = lambda self: self.x + self.y a.f # --> of <__main__.A object at 0x7f4de50d5978>> a.g # --> at 0x7f4de51babf8> Но: >>> A.h = lambda self: self.x + self.y >>> a.h() 3

суббота, 4 января 2020 г.

Перегрузка методов в C# с помощью ref

#c_sharp #net #ооп #методы


Ни как не могу понять в книге написано, что перегрузка методов невозможно с помощь ref



Хотя у меня это получилось 

Another an = new Another();
int a = 0;

an.SomeMethod(a);
an.SomeMethod(ref a);

class Another
{
    public void SomeMethod(int a)
    {
        a = 1;
    }
    public void SomeMethod(ref int a)
    {
        a = 1;
    }
}


Может быть что то не так понял ? 
    


Ответы

Ответ 1



Возможно, это не самый хороший перевод. Запрещена на самом деле вот такая ситуация: class Another { public void SomeMethod(out int a) { a = 1; } public void SomeMethod(ref int a) { a = 1; } } Это производит ошибку CS0063: Cannot define overloaded methods that differ only on ref and out. Причина состоит в том, что на уровне CLR out не существует, и кодируется как ref. Поэтому если бы это было разрешено, с точки зрения CLR это были бы две одинаковые сигнатуры. Отличие out от ref (то есть, то, что out-параметр обязательно должен быть инициализирован внутри метода) — внутреннее правило C#, CLR это не проверяет.

четверг, 2 января 2020 г.

Локальные переменные в Java

#java #ооп #переменные #методы #типы_данных


Собственно говоря, суть моего вопроса можно свести к следующему: почему мы в обязательном
порядке должны присваивать начальное значение локальным переменным, чтобы у нас появилась
возможность их как бы то ни было использовать? Почему для локальных переменных отсутствуют
значения по умолчанию? С чем это может быть связано? 

И ещё один интересный момент, который напрямую связан с моделью памяти в языке программирования
Java. На каком этапе локальная переменная добавляется в стэк? На этапе объявления?
Или всё же на этапе присваивания начального значения? Ведь если мы изначально выделяем
какие-нибудь 4 байта для хранения значения типа int, то конкретное значение у нас уже
имеется (его будет составлять совокупность двоичных разрядов, которые мы уже зарезервировали
под переменную). В общем, хотелось бы разобраться во всех этих вопросах. Всем крайне
благодарен!
    


Ответы

Ответ 1



У компилятора просто нет возможности определить обращаешься ты к проинициализированой переменной в классе или нет, потому на всякий случай им даются стандартные значения. А вот для локальных переменных можно отследить, что она не была проинициализирована и кинуть ошибку. Изначально, объявив переменную это всего лишь указатель на участок памяти, и содержит она то, что было в этом участке памяти до этого, то есть мусор. Чтобы мусора там не было, переменной нужно присвоить значение. То есть, стандартное значение у переменных класса это скорее костыль, для избежания получения "мусора" из переменной. А для локальных можно кинуть ошибку на стадии компиляции

вторник, 31 декабря 2019 г.

Объясните следующую конструкцию

#java #android #методы #android_intent


public class CheatActivity extends Activity {
    ...
    private boolean mAnswerIsTrue;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_cheat);
        mAnswerIsTrue = getIntent().getBooleanExtra(EXTRA_ANSWER_IS_TRUE, false);
    }
}


а именно часть:

mAnswerIsTrue = getIntent().getBooleanExtra(EXTRA_ANSWER_IS_TRUE, false);

    


Ответы

Ответ 1



Activity можно стартануть через интент. К примеру: Intent intent = new Intent(FirstActivity.this, CheatActivity.class); intent.putExtra(EXTRA_ANSWER_IS_TRUE, message); startActivity(intent); и метод getIntent() возвращает вам интент, которым была запущена данная активити. Далее из интента достается булевая переменная по ключу EXTRA_ANSWER_IS_TRUE Лучше всего вам объяснит официальная документация

Ответ 2



Немного теории: Intent - абстрактное описание выполняемой операции. Intent часто в сети описывают как намерение, для выполнения операции. И это описание довольно удачно из-за того, что Intent мб явным и неявным. Основные использование: В startActivity для запуска Activity. В broadcastIntent для отправки его любым заинтересованным компонентам BroadcastReceiver. В startService (Intent) или в bindService (Intent, ServiceConnection, int) для связи с фоновым сервисом. Наиболее значимое использование - это начало деятельности, где ее можно рассматривать как связь между действиями. Это в основном пассивная структура данных, содержащая абстрактное описание действия, которое необходимо выполнить. Итог: Intent это сущность, которая позволяет связать компоненты приложений, имеет возможность управлять ими и при этом может передать данные между компонентами, что у вас в примере и происходит. Ответ: Стартуем: Intent intent = new Intent(this, CheatActivity.class); intent.putExtra(EXTRA_ANSWER_IS_TRUE, mAnswerIsTrue); startActivity(intent); Намерение запустить с текущего класса -> CheatActivity. Положить в намерение intent (Bundle) по ключу EXTRA_ANSWER_IS_TRUE (String) значение mAnswerIsTrue(boolean). Получаем: mAnswerIsTrue = getIntent().getBooleanExtra(EXTRA_ANSWER_IS_TRUE, false); Мы пытаемся получить переменную mAnswerIsTrue(bool). Для этого мы получаем intent командой getIntent, достаем из intent(Bundle) командой getBooleanExtra бул переменную, в случае если ключ EXTRA_ANSWER_IS_TRUE не существует, то ставим ей дефолтное значение false.

Разница между методом по умолчанию в интерфейсе и обычным методом в классе

#java #классы #методы #интерфейс #java_8


Чем отличаются между собой метод по умолчанию, объявленный в интерфейсе с модификатором
default и обычный метод, объявленный в обычном классе?

(update) Читаю


  Метод по умолчанию представляет собой метод, который объявлен в интерфейсе с модификатором
default; его тело всегда представлено блоком. Он предоставляет реализацию по умолчанию
для любого класса, который реализует интерфейс без перекрытия метода. Методы по умолчанию
отличны от конкретных методов, которые объявляются в классах.

    


Ответы

Ответ 1



default метод не может обращаться к состоянию объекта (полям объекта), так как никакого объекта нет, но может вызвать другие методы и обращаться к статическим данным (константам). default метод позволяет избежать необходимости изменить все классы, которые реализуют этот интерфейс. В классе, реализующим интерфейс с default методами, вы можете их переопределить. interface I1 { // это public static final int i = 0; // но в описании интерфейса public static final можно опустить int i = 0; default void m1() { System.out.println("I1 m1 i = " + i); m2(); } void m2(); } Без default этот класс бы не скомпилировался: public class C1 implements I1 { @Override public void m2() { System.out.println("C1 m2"); } public static void main(String[] args) { new C1().m1(); new C1().m2(); } } Вывод будет следующим: I1 m1 i = 0 C1 m2 C1 m2

Ответ 2



Одно из различий заключается в том, что все методы (в т.ч. и default) в интерфейсе неявно объявлены как public и поменять этот модификатор доступа не получится, а в обычном методе в классе Вы можете сами устанавливать различные модификаторы доступа. UPD: Метод по умолчанию представляет собой метод, который объявлен в интерфейсе с модификатором default; его тело всегда представлено блоком. Он предоставляет реализацию по умолчанию для любого класса, который реализует интерфейс без перекрытия метода. Методы по умолчанию отличны от конкретных методов, которые объявляются в классах. Вы несколько неправильно поняли это предложение. Здесь имелось ввиду то, что если класс реализует интерфейс, который содержит default-метод, то при переопределении в классе этого метода, метод из класса перекроет default-реализацию. Попробуйте сделать акцент на выделенном тексте, тогда поймете о чем я: Он предоставляет реализацию по умолчанию для любого класса, который реализует интерфейс без перекрытия метода. Методы по умолчанию отличны от конкретных методов, которые объявляются в классах. К тому же, если бы здесь имелись ввиду какие-то принципиальные различия, то они здесь же были бы указаны, так как в этом пункте из главы про интерфейсы рассказывается непосредственно про default-методы.

вторник, 24 декабря 2019 г.

Какие существуют методы анализа текста на принадлежность к определенной тематике?

#статический_анализ #алгоритм #методы


С помощью каких алгоритмов/способов можно отличить текст про кулинарию например от
текста про программирование?    


Ответы

Ответ 1



Простейший метод - анализ частоты слов в соответствии с тематическими словарями.

Ответ 2



Латентно-семантический анализ (LSA)

Ответ 3



Самый простой, классический способ - Байесовы классификаторы. Их, например, используют в спам фильтрах. (понятно, что сейчас уже далеко не только их) Есть очень мощная и функциональная библиотека для классификации текстов - DKPro TC.

воскресенье, 22 декабря 2019 г.

Как верно передать “класс” в метод?

#c_sharp #методы


Подскажите, пожалуйста, у меня есть два класса; (Star,Circle)
Есть ли возможность передать данный класс в метод с вызовом его конструктора.

Сейчас использую дженереки, но конструктор не работает

Пример:

public static T getObj( int size, int i) where T : new()
{
   return _objs[i] = new T(new Point(rnd.Next(0, 800), i * 20), new Point(5 - i,
15 - i), new Size(size, size));
}


Сам вызов:

getObj(3, i)


Ошибка: CS0417  'T": при создании экземпляра типа переменной не удается задать аргументы

как верно передать класс в метод заместо "new T"?
    


Ответы

Ответ 1



То, в каком виде пытаетесь это сделать Вы, сделать не получится. Вы не можете наложить ограничение на T, чтобы у него обязательно был конструктор с указанными Вами типами параметров. where T : new() Данное ограничение new работает следующим образом: Оно указывает, что аргумент любого переданного типа должен иметь открытый конструктор без параметров. Как видите, нам это не подходит. Точнее, не совсем.Давайте рассмотрим несколько вариантов решения Вашей проблемы #0. Наследование Раз Вы пытаетесь объединить объекты, значит, они явно наделены общей логикой. А общую логику в ООП принято выносить в абстракции. Давайте так и поступим! Я не знаю деталей реализации Вашей программы, но, судя по названиям, Вы работаете с некими фигурами. Запишем все это дело так: // Абстрактный родительский класс public abstract class Shape { // Свойства, которые будут у всех его потомков public Point A { get; set; } public Point B { get; set; } public Size C { get; set; } // Публичные инициализаторы public Shape() { } // Тот инициализатор, что Вы пытаетесь использовать public Shape(Point A, Point B, Size C) { this.A = A; this.B = B; this.C = C; } } public class Circle : Shape { // Реализовываем нужные инициализаторы public Circle() { } public Circle(Point A, Point B, Size C) : base(A, B, C) { // SOMETHING } } public class Star : Shape { // Реализовываем нужные инициализаторы public Star() { } public Star(Point A, Point B, Size C) : base(A, B, C) { // SOMETHING } } Теперь же давайте изменим Ваш метод: // Добавим ограничение, что T может являться только потомком Shape public static T GetShape(Point A, Point B, Size C) where T : Shape, new() { // Используем инициализатор по умолчанию, установив все свойства вручную T obj = new T { A = A, B = B, C = C }; return obj; } Если же Вам нужно не просто установить значения свойств и в инициализатор спрятана какая-то хитрая логика, то метод можно переписать так: // Добавим ограничение, что T может являться только потомком Shape public static T GetShape(Point A, Point B, Size C) where T : Shape { // Получим тип T Type type = typeof(T); // Вручную сопоставим типы if (type == typeof(Star)) // Преобразуем Star к базовому классу, а после - к T, // который, как указано в ограничении, является Shape return (T)(Shape)new Star(A, B, C); else if (type == typeof(Circle)) // Преобразуем Circle к базовому классу, а после - к T, // который, как указано в ограничении, является Shape return (T)(Shape)new Circle(A, B, C); // Если тип не опознан - выбросим ошибку throw new NotSupportedException(); } Или же можно использовать сопоставление шаблонов из C# 7.0+ (данный вариант представлен больше для демонстрации указанных возможностей языка, чем для использования в реальных проектах): // Добавим ограничение, что T может являться только потомком Shape public static T GetShape(Point A, Point B, Size C) where T : Shape, new() { // Инициализатор по умолчанию // Этот метод подразумевает создание объекта дважды, // что не очень логически верно. Не делайте так) T obj = new T(); // Используем паттерны сопоставления switch (obj) { case Star star: star = new Star(A, B, C); obj = (T)(Shape)star; break; case Circle circle: circle = new Circle(A, B, C); obj = (T)(Shape)circle; break; default: // Тип не распознан throw new NotSupportedException(); } return obj; } #1. Явное обращение к рефлексии То, что Вы хотите, можно реализовать и с помощью нашей дорогой и любимой рефлексии (однако сразу предупреждаю, что это медленнее вышеописанного подхода. Не очень заметно на малых выборках, но все же именно поэтому рекомендуется использовать варианты выше) От слов к делу: public static T GetShape(Point A, Point B, Size C) { // Получим тип T Type type = typeof(T); // Получаем открытый конструктор, в который надо передать два объекта типа Point и один типа Size ConstructorInfo constructor = type.GetConstructor(new Type[] { typeof(Point), typeof(Point), typeof(Size) }); if (constructor != null) { try { // Вызовем конструктор с указанными параметрами object result = constructor.Invoke(new object[] { A, B, C }); // Если все прошло удачно, то приведем результат к указанному типу и вернем if (result != null) return (T)result; } catch (Exception ex) { // Ошибочка вышла, обработайте ее! throw new NotSupportedException(); } } // У нас ничего не вышло, значит, тип не соответсвует заданным условиям throw new NotSupportedException(); } Метод можно порядком ужать. Я все расписываю, чтобы Вам было удобнее и понятнее читать) Как ужать? Таким образом, используя Activator.CreateInstance: public static T GetShape(Point A, Point B, Size C) { try { return (T)Activator.CreateInstance(typeof(T), A, B, C); } catch (Exception ex) { // Обработайте ошибку. Ее появление означает, // что у заданного типа нет нужного конструктора throw new NotSupportedException(); } } Данный метод делает ровно то, что и предыдущий (описанный для Вашего лучшего понимания подноготной), только встроенными возможностями С помощью рефлексии можно реализовать метод безо всякого наследования и сопоставления типов, так что метод динамически расширяем (то есть если Вы добавите еще 10 классов, реализующих указанный конструктор, Вам не придется менять данный метод для их создания, в отличие от описанных выше с помощью наследования) UPD: Спасибо @PashaPash за поправку! Итак, согласно документации T obj = new T(); также использует рефлексию для создания объекта.То есть данное выражение эквивалентно следующему: T obj = Activator.CreateInstance(); Надеюсь, мой ответ помог Вам разобраться в вопросе и решил Вашу проблему! Удачи в Ваших начинаниях!

понедельник, 16 декабря 2019 г.

Метод Рунге-Кутты 4 порядка на java

#java #методы #численные_методы


Я только начала изучать java, и многие элементарные вещи для меня являются непонятными.

Прощу вас подсказать мне, как решать систему взаимозависимых уравнений методом Рунге-Кутты!

Полное задание:

Для решения полученной задачи Коши для системы первого порядка вида:

y'= f(t,y), y(0)=y0

использовать метод Рунге_Кутты 4-го порядка точности:

k1 = f(tn , yn)
 k2 = f(tn + h/2 , yn + hk1 / 2)
 k3 = f(tn + h/2 , yn + hk2 / 2)
 k4 = f(tn + h , yn + h*k3)

yn+1=yn+h*(k1 + 2*k2 + 2*k3 + k4) / 6    

На отрезке [0,5] с точным решением 

y1=cos(x)/(1+e2x)1/2,

y2=sin(x)/(1+e2x)1/2.

Для проверки правильности работы программы решить тестовую задачу из двух уравнений:

y1' = –y2 + y1(y12 + y22 – 1),

y2' = y1 + y2(y12 + y22 – 1),

На отрезке [0,5] с точным решением 

y1=cos(x)/(1+e2x)1/2,

y2=sin(x)/(1+e2x)1/2.

Я пытаюсь реализовать только метод!
Сложность заключается в том, что производные у1 и у2 зависят друг от друга.
И правильно ли  я сделала, что производную в точке вычисляю по у1 и у2

public static double y1=Math.cos(x)/Math.pow(1 + Math.pow(Math.E, 2 * x),0.5);
public static double y2=Math.sin(x)/Math.pow(1+Math.pow(Math.E,2*x),0.5);

//   dy1/dx
public static double derviY1(double x,double y10,double y20){

    return -y20+y10*(Math.pow(y10,2)+Math.pow(y20,2)-1);
}

//   dy2/dx
public static  double derviY2(double x ,double y1,double y2){
    return y1 + y2*(Math.pow(y1,2) + Math.pow(y2,2) - 1);
}


И почему-то вычисляя y20[i+1] и y10[i+1] они у меня остаются неизменными, хотя я
в программе изменяю данные, которые в них входят.

for (int i = 0; i < n - 1; i++) {
    x = i * h;

    k1 = h * derviY1(x, y10[i], y20[i]);
    m1 = h * derviY2(x, y10[i], y20[i]);

    k2 = h * derviY1(x + h / 2, y10[i] + k1 / 2, y20[i] + k1 / 2);
    m2 = h * derviY2(x + h / 2, y10[i] + m1 / 2, y20[i] + m1 / 2);

    k3 = h * derviY1(x + h / 2, y10[i] + k2 / 2, y20[i] + k2 / 2);
    m3 = h * derviY2(x + h / 2, y10[i] + m2 / 2, y20[i] + m2 / 2);

    k4 = h * derviY1(x + h, y10[i] + k3, y20[i] + k3);
    m4 = h * derviY2(x + h, y10[i] + m3, y20[i] + m3);

    y10[i + 1] = y10[i] + h * (k1 + 2 * k2 + 2 * k3 + k4) / 6;
    y20[i + 1] = y20[i] + h * (m1 + 2 * m2 + 2 * m3 + m4) / 6;

    System.out.println("| " + x + " |" + " " + y10[i] + " " + "|" + " " + y20[i]
+ " " + "|");


Полный код программы:

import java.*;
import java.lang.Math.*;
import static java.lang.System.out;

public class Test {

    static double x;
    //start
    private static int a = 0;
    // stop
    private static int b = 5;

    public static double y1 = Math.cos(x) / Math.pow(1 + Math.pow(Math.E, 2 * x), 0.5);
    public static double y2 = Math.sin(x) / Math.pow(1 + Math.pow(Math.E, 2 * x), 0.5);

    //   dy1/dx
    public static double derviY1(double x, double y10, double y20) {

        return -y20 + y10 * (Math.pow(y10, 2) + Math.pow(y20, 2) - 1);
    }

    //   dy2/dx
    public static double derviY2(double x, double y1, double y2) {
        return y1 + y2 * (Math.pow(y1, 2) + Math.pow(y2, 2) - 1);
    }


    public static void main(String[] args) {
        int n = 10;
        double h = (b - a) / n;
        double k1, k2, k3, k4, m1, m2, m3, m4;
        double[] y10 = new double[n]; //array of values y1
        double[] y20 = new double[n]; //array of values y2
        y10[0] = 1 / Math.sqrt(2);
        y20[0] = 0;

        // Computation by 4th order Runge-Kutta
        //update x
        for (int i = 0; i < n - 1; i++) {
            x = i * h;

            k1 = h * derviY1(x, y10[i], y20[i]);
            m1 = h * derviY2(x, y10[i], y20[i]);

            k2 = h * derviY1(x + h / 2, y10[i] + k1 / 2, y20[i] + k1 / 2);
            m2 = h * derviY2(x + h / 2, y10[i] + m1 / 2, y20[i] + m1 / 2);

            k3 = h * derviY1(x + h / 2, y10[i] + k2 / 2, y20[i] + k2 / 2);
            m3 = h * derviY2(x + h / 2, y10[i] + m2 / 2, y20[i] + m2 / 2);

            k4 = h * derviY1(x + h, y10[i] + k3, y20[i] + k3);
            m4 = h * derviY2(x + h, y10[i] + m3, y20[i] + m3);

            y10[i + 1] = y10[i] + h * (k1 + 2 * k2 + 2 * k3 + k4) / 6;
            y20[i + 1] = y20[i] + h * (m1 + 2 * m2 + 2 * m3 + m4) / 6;

            System.out.println("| " + x + " |" + " " + y10[i] + " " + "|" + " " +
y20[i] + " " + "|");
        }
    }
}

    


Ответы

Ответ 1



У вас h = 0. Почему? Ведь вы ясно написали, что h = (5-0)/10. А проблема вот в чём. Ваше выражение (5-0)/10 сначала преобразуется в int, а потом уже в double. То есть происходит всё как-то так (int)((5-0)/10). После этой операции мантисса отбрасывается и получается полноценный 0. Достаточно привести к double одну из переменных, как всё выражение будет обработано, как для переменных с плавающей точкой. К примеру так: double h = ((double)b - a) / n; В этих преобразованиях есть более интересные моменты, о которых хотелось бы рассказать, то это уже другая история.