将两个值(正数或负数)缩放到0到1之间的算法

huangapple go评论64阅读模式
英文:

Algorithm for scaling two values (positive or negative) to between 0 and 1

问题

我理解了您的请求,以下是您提供的代码的翻译部分:

我正在寻找一个可以缩放和合并两个数字的算法:

```swift
func scale(x: Int, y: Int) -> Double { 
    // 在这里编写算法
    return 0.5
}

该算法必须满足以下约束条件:

  • 返回值在 01 之间
  • 如果 xy 相同,则返回 0.5
  • 如果 xy "更大",则返回某个大于 0.5 的数
  • 如果 yx "更大",则返回某个小于 0.5 的数
  • 返回值是相对的,因此 scale(x: -5, y: 4) < scale(x: -5, y: 0) == True
  • 注:-1 比 -2 "更大"

以下是测试套件(用于在 Swift Playground 中使用):

import Foundation
import XCTest

func XCTAssertBetween(_ value: Double, _ range: ClosedRange<Double>, _ message: @autoclosure () -> String = "", file: StaticString = #file, line: UInt = #line) {
    XCTAssertGreaterThanOrEqual(value, range.lowerBound, "Value is less than lower bound", file: file, line: line)
    XCTAssertLessThanOrEqual(value, range.upperBound, "Value is more than upper bound", file: file, line: line)
}

class ScaleTests: XCTestCase {
    func testZZ() {
        XCTAssertEqual(scale(x: 0, y: 0), 0.5)
    }
    
    func testPP() {
        XCTAssertEqual(scale(x: 1, y: 1), 0.5)
    }
    
    func testPZ() {
        XCTAssertBetween(scale(x: 1, y: 0), 0.51...1)
    }
    
    func testZP() {
        XCTAssertBetween(scale(x: 0, y: 1), 0...0.49)
    }
    
    func testNN() {
        XCTAssertEqual(scale(x: -1, y: -1), 0.5)
    }
    
    func testZN() {
        XCTAssertBetween(scale(x: 0, y: -1), 0.51...1)
    }
    
    func testNZ() {
        XCTAssertBetween(scale(x: -1, y: 0), 0...0.49)
    }
}
  
ScaleTests.defaultTestSuite.run()

如果您需要进一步的帮助,请随时告诉我。

英文:

I'm looking for an algorithm that will scale and consolidate two numbers:

func scale(x: Int, y: Int) -&gt; Double { 
    // algorithm here
    return 0.5
}

The algorithm must satisfy the following constraints:

  • Return values between 0 and 1
  • If x and y are the same return 0.5
  • If x is "bigger"* than y return some number &gt; 0.5
  • If y is "bigger"* than x return some number &lt; 0.5
  • Return values are relative, so scale(x: -5, y: 4) &lt; scale(x: -5, y: 0) == True
  • * -1 is "bigger" than -2

Here's the test suite (for use in a Swift Playground):

import Foundation
import XCTest

func XCTAssertBetween(_ value: Double, _ range: ClosedRange&lt;Double&gt;, _ message: @autoclosure () -&gt; String = &quot;&quot;, file: StaticString = #file, line: UInt = #line) {
    XCTAssertGreaterThanOrEqual(value, range.lowerBound, &quot;Value is less than lower bound&quot;, file: file, line: line)
    XCTAssertLessThanOrEqual(value, range.upperBound, &quot;Value is more than upper bound&quot;, file: file, line: line)
}

class ScaleTests: XCTestCase {
    func testZZ() {
        XCTAssertEqual(scale(x: 0, y: 0), 0.5)
    }
    
    func testPP() {
        XCTAssertEqual(scale(x: 1, y: 1), 0.5)
    }
    
    func testPZ() {
        XCTAssertBetween(scale(x: 1, y: 0), 0.51...1)
    }
    
    func testZP() {
        XCTAssertBetween(scale(x: 0, y: 1), 0...0.49)
    }
    
    func testNN() {
        XCTAssertEqual(scale(x: -1, y: -1), 0.5)
    }
    
    func testZN() {
        XCTAssertBetween(scale(x: 0, y: -1), 0.51...1)
    }
    
    func testNZ() {
        XCTAssertBetween(scale(x: -1, y: 0), 0...0.49)
    }
}
  
ScaleTests.defaultTestSuite.run()

答案1

得分: 2

你在描述的是一个sigmoid函数,任何经过适当缩放的sigmoid函数都可以实现这个效果。从你的差异开始:

let d = Double(x) - Double(y)

一些示例的缩放sigmoid函数:

return 1 / (1 + exp(-d)) // Logistic function as emehex demonstrated

return atan(d) / .pi + 0.5

return tanh(d) / 2 + 0.5 // Another form of the logistic

return 0.5 + d / (2*sqrt(1 + d * d))

Logistic函数是在这种情况下传统上要使用的函数,但出于性能或其他特性的考虑,你可能希望使用其他函数。

正如@emehex所指出的,Logistic函数可能会在你的范围内将值聚集得比你想要的更多。你可以通过重新缩放d,乘以或除以你喜欢的任何值来修复这个问题,以获得你想要的“陡度”。

根据你使用这个功能的频率,你可能希望查看Apple生态系统中提供的一些sigmoid函数。在机器学习应用中,这个函数非常常见。

英文:

What you're describing is a sigmoid function, and any properly scaled sigmoid will do this. Starting with your difference:

let d = Double(x) - Double(y)

Some example scaled Sigmoids:

return 1 / (1 + exp(-d)) // Logistic function as emehex demonstrated

return atan(d) / .pi + 0.5

return tanh(d) / 2 + 0.5 // Another form of the logistic

return 0.5 + d / (2*sqrt(1 + d * d))

The logistic function is the traditional one to use in this case, but you may want others for performance or other characteristics.

As @emehex notes, the logistic function may bunch up the values more than you like within your scale. You can fix that by rescaling d, multiplying or dividing it by whatever you like to get the "steepness" you want.

Depending on how much you're using this, you may want to look at one of the several sigmoid functions available in the Apple ecosystem. This function is extremely common in machine learning applications.

答案2

得分: -1

这很接近(它满足所有测试):

func scale(x: Int, y: Int) -&gt; Double {
    let val = Double(x - y)
    return 1 / (1 + exp(-val))
}

但我不喜欢所有这些都约等于0.99:

scale(x: 5, y: 0) // 希望这是大约0.8
scale(x: 10, y: 0) // 大约0.90
scale(x: 20, y: -10) // 大约0.99
英文:

This is close (it satisfies all of the tests):

func scale(x: Int, y: Int) -&gt; Double {
    let val = Double(x - y)
    return 1 / (1 + exp(-val))
}

But I don't love that all of these are ~= 0.99:

scale(x: 5, y: 0) // wish this was 0.8-ish
scale(x: 10, y: 0) // 0.90-ish
scale(x: 20, y: -10) // 0.99-ish

huangapple
  • 本文由 发表于 2023年6月9日 03:39:11
  • 转载请务必保留本文链接:https://go.coder-hub.com/76435204.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定