001// Copyright (c) FIRST and other WPILib contributors. 002// Open Source Software; you can modify and/or share it under the terms of 003// the WPILib BSD license file in the root directory of this project. 004 005package edu.wpi.first.units; 006 007import java.util.Objects; 008 009/** 010 * A function that accepts a single {@code double} and returns a {@code double} result. This is used 011 * to represent arbitrary mapping functions for converting units to and from a base unit 012 * representation. Temperature units, in particular, typically have an offset from a value in Kelvin 013 * and may have a multiplication factor added in, which means that units cannot always be 014 * represented as simple ratios of their base units. 015 */ 016@FunctionalInterface 017public interface UnaryFunction { 018 /** The identity function that simply returns the input value. */ 019 UnaryFunction IDENTITY = x -> x; 020 021 /** 022 * Applies this function to the input value and returns the result. 023 * 024 * @param input the input value to the function 025 * @return the result 026 */ 027 double apply(double input); 028 029 /** 030 * Constructs a new function that first calls this function, then passes the result to another as 031 * input. 032 * 033 * <pre> 034 * f = x -> x + 1 // f(x) = x + 1 035 * g = x -> 2 * x // g(x) = 2x 036 * 037 * h = f.pipeTo(g) // h(x) = g(f(x)) 038 * </pre> 039 * 040 * @param next the next operation to pipe to 041 * @return the composite function g(f(x)) 042 */ 043 default UnaryFunction pipeTo(UnaryFunction next) { 044 Objects.requireNonNull(next, "The next operation in the chain must be provided"); 045 046 return x -> next.apply(this.apply(x)); 047 } 048 049 /** 050 * Creates a composite function h(x) such that h(x) = f(x) * g(x). 051 * 052 * @param multiplier the function to multiply this one by 053 * @return the composite function f(x) * g(x) 054 */ 055 default UnaryFunction mult(UnaryFunction multiplier) { 056 Objects.requireNonNull(multiplier, "A multiplier function must be provided"); 057 058 return x -> this.apply(x) * multiplier.apply(x); 059 } 060 061 /** 062 * Creates a composite function h(x) such that h(x) = k * f(x). 063 * 064 * @param multiplier the constant value to multiply this function's results by 065 * @return the composite function k * f(x) 066 */ 067 default UnaryFunction mult(double multiplier) { 068 return x -> this.apply(x) * multiplier; 069 } 070 071 /** 072 * Creates a composite function h(x) such that h(x) = f(x) / g(x). 073 * 074 * @param divisor the function to divide this one by 075 * @return the composite function f(x) / g(x) 076 */ 077 default UnaryFunction div(UnaryFunction divisor) { 078 Objects.requireNonNull(divisor, "A divisor function must be provided"); 079 080 return x -> { 081 double numerator = this.apply(x); 082 083 // fast-track to avoid another function call 084 // avoids returning NaN if divisor is also zero 085 if (numerator == 0) { 086 return 0; 087 } 088 089 double div = divisor.apply(x); 090 return numerator / div; // NOTE: returns +Infinity or -Infinity if div is zero 091 }; 092 } 093 094 /** 095 * Creates a composite function h(x) such that h(x) = 1/k * f(x). 096 * 097 * @param divisor the constant value to divide this function's results by 098 * @return the composite function 1/k * f(x) 099 */ 100 default UnaryFunction div(double divisor) { 101 return x -> this.apply(x) / divisor; 102 } 103 104 /** 105 * Creates a composite function h(x) such that h(x) = f(x) ^ g(x). 106 * 107 * @param exponent the function to exponentiate this function's results by 108 * @return the composite function f(x) ^ g(x) 109 */ 110 default UnaryFunction exp(UnaryFunction exponent) { 111 Objects.requireNonNull(exponent, "An exponent function must be provided"); 112 113 return x -> Math.pow(this.apply(x), exponent.apply(x)); 114 } 115 116 /** 117 * Creates a composite function h(x) such that h(x) = f(x) ^ k. 118 * 119 * @param exponent the constant value to exponentiate this function's results by 120 * @return the composite function f(x) ^ k 121 */ 122 default UnaryFunction exp(double exponent) { 123 return x -> Math.pow(this.apply(x), exponent); 124 } 125}