Time ago I did a research trying to find a solution to calculate aspect ratio of a resolution, and this answer helped me to write the code below, which works fine for all common resolutions, but I just discovered that it fails to calculate the aspect ratio for many other resolutions, for example my code below will give a result value of "683:384" when trying to calculate the aspect ratio for "1366x768" resolution, which, according to Google results it is "almost" 16:9, so my calculation is wrong.
The aspect ratio of 1366x768 is 1366:768, which is almost 16:9, although more precisely 16:8.9956076
It fails for many other untypical resolutions.
My question is: what I'm doing wrong in the calculation of the aspect ratio and how do I fix it?.
EDIT: After researching a bit, I partially understood that the GCD approach is not viable for these kind of resolutions as mentioned here:
https://stackoverflow.com/a/10070517/1248295
However, having a table of "known display aspect ratios" as suggested in that thread I'm not sure if it is a viable solution, and I'm not sure how to apply that to the calculation.
Here is my current code:
''' <summary>Calculate the aspect ratio of the source resolution.</summary>
''' <returns>The resulting aspect ratio, expressed as X:Y.</returns>
Public Shared Function GetAspectRatio(resolution As Size) As Point
Dim gcd As Integer = GetGreatestCommonDivisor(resolution.Width, resolution.Height)
Return New Point((resolution.Width \ gcd), (resolution.Height \ gcd))
End Function
''' <summary>
''' Gets the Greatest Common Divisor (GCD) of one or more values.
''' <para></para>
''' That is, the largest positive value that divides each of the given values. For example, the GCD of 8 and 12 is 4.
''' </summary>
''' <remarks>
''' Wikipedia article: <see href="https://en.wikipedia.org/wiki/Greatest_common_divisor"/>
''' <para></para>
''' Original solution in C#: <see href="https://stackoverflow.com/a/41766138/1248295"/>
''' </remarks>
Public Shared Function GetGreatestCommonDivisor(ParamArray values As Integer()) As Integer
Dim dblValues As Double() = Array.ConvertAll(values, Function(value) CDbl(value))
Return CInt(dblValues.Aggregate(AddressOf InternalGetGreatestCommonDivisor))
End Function
Private Shared Function InternalGetGreatestCommonDivisor(first As Double, second As Double) As Double
If (first < 0) Then
first = Math.Abs(first)
End If
If (second < 0) Then
second = Math.Abs(second)
End If
' ReSharper disable CompareOfFloatsByEqualityOperator
Do While (first <> 0) AndAlso (second <> 0)
If (first > second) Then
first = (first Mod second)
Else
second = (second Mod first)
End If
Loop
Return If(first = 0, second, first)
' ReSharper restore CompareOfFloatsByEqualityOperator
End Function
Example usage:
Dim resolutions As Size() = {
New Size(640, 480),
New Size(800, 600),
New Size(1280, 720),
New Size(1920, 1080),
New Size(1366, 768)
}
For Each res As Size In resolutions
Dim aspectRatio As Point = GetAspectRatio(res)
Console.WriteLine($"Resolution: {res.Width}x{res.Height}, Aspect Ratio: {aspectRatio.X}:{aspectRatio.Y}")
Next
That will produce this output:
Resolution: 640x480, Aspect Ratio: 4:3
Resolution: 800x600, Aspect Ratio: 4:3
Resolution: 1280x720, Aspect Ratio: 16:9
Resolution: 1920x1080, Aspect Ratio: 16:9
Resolution: 1366x768, Aspect Ratio: 683:384