Обратные тригонометрические функции возвращают неправильные значения градусов в калькуляторе KotlinAndroid

Форум для тех, кто программирует под Android
Ответить
Anonymous
 Обратные тригонометрические функции возвращают неправильные значения градусов в калькуляторе Kotlin

Сообщение Anonymous »

1) Неправильные выходные данные для режима степени:
  • asin(0.5) должен возвращать30 градусов, но в настоящее время он возвращает 0,5000063464.
  • acos(0.5) должен возвращать 60 градусов, но в настоящее время он возвращает 89,499993654 .
  • atan(1) должен возвращать 45 градусов, но в настоящее время он возвращает 0,9998984794.
2) Пределы проверки применяются неправильно в режиме степени:
  • Проверка ввода (validateInverseTrigArgument) проверяет только то, что аргументы находятся в диапазоне [-1, 1], который подходит для радиан, но не применим к градусам.
    < /ul>
    Это код, который является частью класса Evaluator:

    Код: Выделить всё

        fun setRadianMode(isRadian: Boolean) {
    isRadianMode = isRadian
    }
    
    fun isInRadianMode(): Boolean = isRadianMode
    
    // Validate arguments for inverse trig functions
    private fun validateInverseTrigArgument(func: String, argument: String): Boolean {
    return try {
    val value = symbols.eval(argument)
    when (func) {
    "asin", "acos" -> value in -1.0..1.0
    else -> true
    }
    } catch (e: Exception) {
    false  // If evaluation fails, consider it invalid
    }
    }
    
    private fun convertTrigFunctions(expression: String): String {
    val trigFunctions = listOf("sin", "cos", "tan", "cot")
    val inverseTrigFunctions = listOf("asin", "acos", "atan", "acot")
    var modifiedExpression = expression
    
    // First handle regular trig functions
    for (func in trigFunctions) {
    val regex = "$func\\(".toRegex()
    val matches = regex.findAll(modifiedExpression)
    
    for (match in matches.toList().reversed()) {
    val startIndex = match.range.last + 1
    val endIndex = try {
    findMatchingParenthesis(modifiedExpression, startIndex)
    } catch (e: IllegalArgumentException) {
    // If no closing parenthesis, treat end of expression as the closing point
    modifiedExpression.length
    }
    
    val argument = modifiedExpression.substring(startIndex, endIndex)
    
    val convertedArgument = if (!isRadianMode) {
    "$func($argument * $PI / 180)"
    } else {
    "$func($argument)"
    }
    
    modifiedExpression = modifiedExpression.replaceRange(match.range.first, endIndex, convertedArgument)
    }
    }
    
    // Then handle inverse trig functions separately
    for (func in inverseTrigFunctions) {
    val regex = "$func\\(".toRegex()
    val matches = regex.findAll(modifiedExpression)
    
    for (match in matches.toList().reversed()) {
    val startIndex = match.range.last + 1
    val endIndex = try {
    findMatchingParenthesis(modifiedExpression, startIndex)
    } catch (e: IllegalArgumentException) {
    modifiedExpression.length
    }
    
    val argument = modifiedExpression.substring(startIndex, endIndex)
    
    // Convert output of inverse trig function to degrees if in degree mode
    val convertedArgument = if (!isRadianMode) {
    "$func($argument) * 180 / $PI"
    } else {
    "$func($argument)"
    }
    
    modifiedExpression = modifiedExpression.replaceRange(match.range.first, endIndex, convertedArgument)
    }
    }
    
    return modifiedExpression
    }
    
    Я использую Javia Arity/Arithmetic для оценки выражений:
    https://github.com/preda/arithmetic
    Я попробовал это с математической библиотекой Java, но безуспешно

    Код: Выделить всё

    private fun evaluateInverseTrigFunction(func: String, argument: Double): Double {
    val result = when (func) {
    "asin" -> Math.asin(argument)
    "acos" -> Math.acos(argument)
    "atan"  -> Math.atan(argument)
    else -> throw IllegalArgumentException("Invalid function: $func")
    }
    
    // Convert to degrees if not in radian mode
    return if (!isRadianMode) result * 180 / Math.PI else result
    }
    
    private fun convertTrigFunctions(expression: String): String {
    val trigFunctions = listOf("sin", "cos", "tan", "cot")
    val inverseTrigFunctions = listOf("asin", "acos", "atan", "acot")
    var modifiedExpression = expression
    
    // Handle regular trig functions as before
    for (func in trigFunctions) {
    val regex = "$func\\(".toRegex()
    val matches = regex.findAll(modifiedExpression)
    
    for (match in matches.toList().reversed()) {
    val startIndex = match.range.last + 1
    val endIndex = try {
    findMatchingParenthesis(modifiedExpression, startIndex)
    } catch (e: IllegalArgumentException) {
    modifiedExpression.length
    }
    
    val argument = modifiedExpression.substring(startIndex, endIndex)
    
    val convertedArgument = if (!isRadianMode) {
    "$func($argument * $PI / 180)"
    } else {
    "$func($argument)"
    }
    
    modifiedExpression = modifiedExpression.replaceRange(match.range.first, endIndex, convertedArgument)
    }
    }
    
    // Handle inverse trig functions
    for (func in inverseTrigFunctions) {
    val regex = "$func\\(([^)]+)\\)".toRegex() // Match function argument inside parentheses
    val matches = regex.findAll(modifiedExpression)
    
    for (match in matches.toList().reversed()) {
    val argumentStr = match.groupValues[1]
    
    // Evaluate the argument expression as a Double
    val argument = symbols.eval(argumentStr)
    
    // Get result from evaluateInverseTrigFunction
    val result = evaluateInverseTrigFunction(func, argument)
    
    // Replace original function call with the computed result
    modifiedExpression = modifiedExpression.replaceRange(match.range, result.toString())
    }
    }
    
    return modifiedExpression
    }
    
    Обратные триггерные функции: когда ConvertTrigFunctions обнаруживает обратную триггерную функцию (например, asin, acos, atan):
  • Он извлекает аргумент и оценивает его как Double.
  • Он вызывает функцию AssessmentInverseTrigFunction, которая вычисляет результат и применяет преобразование степени, если isRadianMode имеет значение false.
  • Он заменяет исходный вызов функции в выражении вычисленным результатом.
UNIT Результаты тестового примера:

Код: Выделить всё

    fun testAsinInDegreeMode() {
println("Test asin function in degree mode:")
evaluator.setRadianMode(false)
val result = evaluator.evaluate("asin(0.5)")
assertEquals("30", result) // asin(0.5) in degrees is 30
}
Проверка функции asin в режиме степени:

org.junit.ComparisonFailure:

Ожидается: 30

Фактическое значение: 0,5000063464
Проверить функцию acos в режиме степени:

org.junit.ComparisonFailure:

Ожидаемое: 60

Фактическое: 89,499993654
Проверка функции в градусном режиме:

org.junit.ComparisonFailure:

Ожидается: 45

Фактическое: 0,9998984794

Код: Выделить всё

    fun testInvalidAsinArgument() {
println("Test invalid argument for asin in degree mode (greater than 1):")
evaluator.setRadianMode(false)
val result = evaluator.evaluate("asin(2.0)")
assertEquals("Error: Unable to show the result", result)
}
Проверить недопустимый аргумент для asin в режиме степени (больше 1):

org.junit.ComparisonFailure:

Ожидается: ошибка: невозможно показать результат

Факт: 2.0004063794
Проверьте неверный аргумент для acos в режиме степени (больше 1):

org.junit.ComparisonFailure:

Ожидается: Ошибка: невозможно показать результат

Фактическое :87.999593621


Подробнее здесь: https://stackoverflow.com/questions/791 ... in-calcula
Ответить

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

Вернуться в «Android»