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 /** 019 * Applies this function to the input value and returns the result. 020 * 021 * @param input the input value to the function 022 * @return the result 023 */ 024 double apply(double input); 025 026 /** 027 * Constructs a new function that first calls this function, then passes the result to another as 028 * input. 029 * 030 * <pre> 031 * f = x -> x + 1 // f(x) = x + 1 032 * g = x -> 2 * x // g(x) = 2x 033 * 034 * h = f.pipeTo(g) // h(x) = g(f(x)) 035 * </pre> 036 * 037 * @param next the next operation to pipe to 038 * @return the composite function g(f(x)) 039 */ 040 default UnaryFunction pipeTo(UnaryFunction next) { 041 Objects.requireNonNull(next, "The next operation in the chain must be provided"); 042 043 return x -> next.apply(this.apply(x)); 044 } 045 046 /** 047 * Creates a composite function h(x) such that h(x) = f(x) * g(x). 048 * 049 * @param multiplier the function to multiply this one by 050 * @return the composite function f(x) * g(x) 051 */ 052 default UnaryFunction mult(UnaryFunction multiplier) { 053 Objects.requireNonNull(multiplier, "A multiplier function must be provided"); 054 055 return x -> this.apply(x) * multiplier.apply(x); 056 } 057 058 /** 059 * Creates a composite function h(x) such that h(x) = k * f(x). 060 * 061 * @param multiplier the constant value to multiply this function's results by 062 * @return the composite function k * f(x) 063 */ 064 default UnaryFunction mult(double multiplier) { 065 return x -> this.apply(x) * multiplier; 066 } 067 068 /** 069 * Creates a composite function h(x) such that h(x) = f(x) / g(x). 070 * 071 * @param divisor the function to divide this one by 072 * @return the composite function f(x) / g(x) 073 */ 074 default UnaryFunction div(UnaryFunction divisor) { 075 Objects.requireNonNull(divisor, "A divisor function must be provided"); 076 077 return x -> { 078 double numerator = this.apply(x); 079 080 // fast-track to avoid another function call 081 // avoids returning NaN if divisor is also zero 082 if (numerator == 0) { 083 return 0; 084 } 085 086 double div = divisor.apply(x); 087 return numerator / div; // NOTE: returns +Infinity or -Infinity if div is zero 088 }; 089 } 090 091 /** 092 * Creates a composite function h(x) such that h(x) = 1/k * f(x). 093 * 094 * @param divisor the constant value to divide this function's results by 095 * @return the composite function 1/k * f(x) 096 */ 097 default UnaryFunction div(double divisor) { 098 return x -> this.apply(x) / divisor; 099 } 100 101 /** 102 * Creates a composite function h(x) such that h(x) = f(x) ^ g(x). 103 * 104 * @param exponent the function to exponentiate this function's results by 105 * @return the composite function f(x) ^ g(x) 106 */ 107 default UnaryFunction exp(UnaryFunction exponent) { 108 Objects.requireNonNull(exponent, "An exponent function must be provided"); 109 110 return x -> Math.pow(this.apply(x), exponent.apply(x)); 111 } 112 113 /** 114 * Creates a composite function h(x) such that h(x) = f(x) ^ k. 115 * 116 * @param exponent the constant value to exponentiate this function's results by 117 * @return the composite function f(x) ^ k 118 */ 119 default UnaryFunction exp(double exponent) { 120 return x -> Math.pow(this.apply(x), exponent); 121 } 122}